diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3ec182d4..ff42532cc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,216 +1,207 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Jun 14 2010 -# @date last modification: Wed Jan 20 2016 +# @date last modification: Tue Feb 13 2018 # # @brief CMake file for the library # # @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) +# Copyright (©) 2010-2018 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 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. +# 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 <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU Lesser General Public License along with Akantu. If not, see <http://www.gnu.org/licenses/>. # #=============================================================================== #=============================================================================== # Package Management #=============================================================================== package_get_all_source_files( AKANTU_LIBRARY_SRCS AKANTU_LIBRARY_PUBLIC_HDRS AKANTU_LIBRARY_PRIVATE_HDRS ) package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) package_get_all_external_informations( PRIVATE_INCLUDE AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR LIBRARIES AKANTU_EXTERNAL_LIBRARIES ) package_get_all_compilation_flags(CXX _cxx_flags) set(AKANTU_EXTRA_CXX_FLAGS "${_cxx_flags}" CACHE STRING "Extra flags defined by loaded packages" FORCE) mark_as_advanced(AKANTU_EXTRA_CXX_FLAGS) foreach(src_ ${AKANTU_SPIRIT_SOURCES}) set_property(SOURCE ${src_} PROPERTY COMPILE_FLAGS "-g0 -Werror") endforeach() #=========================================================================== # header for blas/lapack (any other fortran libraries) #=========================================================================== package_is_activated(BLAS _blas_activated) package_is_activated(LAPACK _lapack_activated) if(_blas_activated OR _lapack_activated) if(CMAKE_Fortran_COMPILER) # ugly hack set(CMAKE_Fortran_COMPILER_LOADED TRUE) endif() include(FortranCInterface) FortranCInterface_HEADER( "${CMAKE_CURRENT_BINARY_DIR}/aka_fortran_mangling.hh" MACRO_NAMESPACE "AKA_FC_") mark_as_advanced(CDEFS) endif() list(APPEND AKANTU_LIBRARY_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}") set(AKANTU_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} ${AKANTU_LIBRARY_INCLUDE_DIRS} CACHE INTERNAL "Internal include directories to link with Akantu as a subproject") #=========================================================================== # configurations #=========================================================================== package_get_all_material_includes(AKANTU_MATERIAL_INCLUDES) package_get_all_material_lists(AKANTU_MATERIAL_LISTS) configure_file(model/solid_mechanics/material_list.hh.in "${CMAKE_CURRENT_BINARY_DIR}/material_list.hh" @ONLY) package_get_element_lists() configure_file(common/aka_element_classes_info.hh.in "${CMAKE_CURRENT_BINARY_DIR}/aka_element_classes_info.hh" @ONLY) configure_file(common/aka_config.hh.in "${CMAKE_CURRENT_BINARY_DIR}/aka_config.hh" @ONLY) #=============================================================================== # Debug infos #=============================================================================== set(AKANTU_GDB_DIR ${PROJECT_SOURCE_DIR}/cmake) if(UNIX) string(TOUPPER "${CMAKE_BUILD_TYPE}" _u_build_type) if(_u_build_type STREQUAL "DEBUG" OR _u_build_type STREQUAL "RELWITHDEBINFO") configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in "${PROJECT_BINARY_DIR}/libakantu-gdb.py" @ONLY) configure_file(${PROJECT_SOURCE_DIR}/cmake/akantu-debug.cc.in "${PROJECT_BINARY_DIR}/akantu-debug.cc" @ONLY) list(APPEND AKANTU_LIBRARY_SRCS ${PROJECT_BINARY_DIR}/akantu-debug.cc) endif() else() find_program(GDB_EXECUTABLE gdb) if(GDB_EXECUTABLE) execute_process(COMMAND ${GDB_EXECUTABLE} --batch -x "${PROJECT_SOURCE_DIR}/cmake/gdb_python_path" OUTPUT_VARIABLE AKANTU_PYTHON_GDB_DIR ERROR_QUIET RESULT_VARIABLE _res) if(_res EQUAL 0 AND UNIX) set(GDB_USER_CONFIG $ENV{HOME}/.gdb/auto-load) file(MAKE_DIRECTORY ${GDB_USER_CONFIG}) configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in "${GDB_USER_CONFIG}/${CMAKE_SHARED_LIBRARY_PREFIX}akantu${CMAKE_SHARED_LIBRARY_SUFFIX}.${AKANTU_VERSION}-gdb.py" @ONLY) endif() endif() endif() #=============================================================================== # Library generation #=============================================================================== add_library(akantu ${AKANTU_LIBRARY_SRCS}) target_include_directories(akantu PRIVATE $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}> INTERFACE $<INSTALL_INTERFACE:include/akantu> ) # small trick for build includes in public set_property(TARGET akantu APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}>) target_include_directories(akantu SYSTEM PUBLIC ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR} ) target_include_directories(akantu SYSTEM PRIVATE ${AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR} ) target_link_libraries(akantu ${AKANTU_EXTERNAL_LIBRARIES}) set_target_properties(akantu PROPERTIES ${AKANTU_LIBRARY_PROPERTIES} # this contains the version COMPILE_FLAGS "${_cxx_flags}" ) if(NOT CMAKE_VERSION VERSION_LESS 3.1) package_get_all_features_public(_PUBLIC_features) package_get_all_features_private(_PRIVATE_features) foreach(_type PRIVATE PUBLIC) if(_${_type}_features) target_compile_features(akantu ${_type} ${_${_type}_features}) endif() endforeach() else() set_target_properties(akantu PROPERTIES CXX_STANDARD 14 ) endif() package_get_all_extra_dependencies(_extra_target_dependencies) if(_extra_target_dependencies) # This only adding todo: find a solution for when a dependency was add the is removed... add_dependencies(akantu ${_extra_target_dependencies}) endif() package_get_all_export_list(AKANTU_EXPORT_LIST) list(APPEND AKANTU_EXPORT_LIST akantu) # TODO separate public from private headers install(TARGETS akantu EXPORT ${AKANTU_TARGETS_EXPORT} LIBRARY DESTINATION lib COMPONENT lib ARCHIVE DESTINATION lib COMPONENT lib RUNTIME DESTINATION bin COMPONENT bin PUBLIC_HEADER DESTINATION include/akantu/ COMPONENT dev ) if("${AKANTU_TARGETS_EXPORT}" STREQUAL "AkantuTargets") install(EXPORT AkantuTargets DESTINATION share/cmake/${PROJECT_NAME} COMPONENT dev) #Export for build tree export(EXPORT AkantuTargets FILE "${CMAKE_BINARY_DIR}/AkantuTargets.cmake") export(PACKAGE Akantu) endif() # print out the list of materials generate_material_list() register_target_to_tidy(akantu) diff --git a/src/common/aka_array.cc b/src/common/aka_array.cc index d014ca3ab..9c273ed17 100644 --- a/src/common/aka_array.cc +++ b/src/common/aka_array.cc @@ -1,124 +1,123 @@ /** * @file aka_array.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of akantu::Array * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <memory> #include <utility> /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" namespace akantu { /* -------------------------------------------------------------------------- */ /* Functions ArrayBase */ /* -------------------------------------------------------------------------- */ ArrayBase::ArrayBase(ID id) : id(std::move(id)), allocated_size(0), size_(0), nb_component(1), size_of_type(0) {} /* -------------------------------------------------------------------------- */ ArrayBase::~ArrayBase() = default; /* -------------------------------------------------------------------------- */ void ArrayBase::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ArrayBase [" << std::endl; stream << space << " + size : " << size_ << std::endl; stream << space << " + nb component : " << nb_component << std::endl; stream << space << " + allocated size : " << allocated_size << std::endl; Real mem_size = (allocated_size * nb_component * size_of_type) / 1024.; stream << space << " + size of type : " << size_of_type << "B" << std::endl; stream << space << " + memory allocated : " << mem_size << "kB" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ template <> UInt Array<Real>::find(const Real & elem) const { AKANTU_DEBUG_IN(); Real epsilon = std::numeric_limits<Real>::epsilon(); auto it = std::find_if(begin(), end(), [&elem, &epsilon](auto && a) { return std::abs(a - elem) <= epsilon; }); AKANTU_DEBUG_OUT(); return (it != end()) ? end() - it : UInt(-1); } /* -------------------------------------------------------------------------- */ template <> Array<ElementType> & Array<ElementType>::operator*=(__attribute__((unused)) const ElementType & alpha) { AKANTU_TO_IMPLEMENT(); return *this; } template <> Array<ElementType> & Array<ElementType>:: operator-=(__attribute__((unused)) const Array<ElementType> & vect) { AKANTU_TO_IMPLEMENT(); return *this; } template <> Array<ElementType> & Array<ElementType>:: operator+=(__attribute__((unused)) const Array<ElementType> & vect) { AKANTU_TO_IMPLEMENT(); return *this; } template <> Array<char> & Array<char>::operator*=(__attribute__((unused)) const char & alpha) { AKANTU_TO_IMPLEMENT(); return *this; } template <> Array<char> & Array<char>::operator-=(__attribute__((unused)) const Array<char> & vect) { AKANTU_TO_IMPLEMENT(); return *this; } template <> Array<char> & Array<char>::operator+=(__attribute__((unused)) const Array<char> & vect) { AKANTU_TO_IMPLEMENT(); return *this; } } // namespace akantu diff --git a/src/common/aka_array.hh b/src/common/aka_array.hh index 518b2b062..a75bd18ed 100644 --- a/src/common/aka_array.hh +++ b/src/common/aka_array.hh @@ -1,372 +1,371 @@ /** * @file aka_array.hh * * @author Till Junge <till.junge@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Tue Jan 16 2018 * * @brief Array container for Akantu * This container differs from the std::vector from the fact it as 2 dimensions * a main dimension and the size stored per entries * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_VECTOR_HH__ #define __AKANTU_VECTOR_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <typeinfo> #include <vector> /* -------------------------------------------------------------------------- */ namespace akantu { /// class that afford to store vectors in static memory class ArrayBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit ArrayBase(ID id = ""); virtual ~ArrayBase(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get the amount of space allocated in bytes inline UInt getMemorySize() const; /// set the size to zero without freeing the allocated space inline void empty(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get the real size allocated in memory AKANTU_GET_MACRO(AllocatedSize, allocated_size, UInt); /// Get the Size of the Array UInt getSize() const __attribute__((deprecated)) { return size_; } UInt size() const { return size_; } /// Get the number of components AKANTU_GET_MACRO(NbComponent, nb_component, UInt); /// Get the name of th array AKANTU_GET_MACRO(ID, id, const ID &); /// Set the name of th array AKANTU_SET_MACRO(ID, id, const ID &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the vector ID id; /// the size allocated UInt allocated_size{0}; /// the size used UInt size_{0}; /// number of components UInt nb_component{1}; /// size of the stored type UInt size_of_type{0}; }; /* -------------------------------------------------------------------------- */ namespace { template <std::size_t dim, typename T> struct IteratorHelper {}; template <typename T> struct IteratorHelper<0, T> { using type = T; }; template <typename T> struct IteratorHelper<1, T> { using type = Vector<T>; }; template <typename T> struct IteratorHelper<2, T> { using type = Matrix<T>; }; template <typename T> struct IteratorHelper<3, T> { using type = Tensor3<T>; }; template <std::size_t dim, typename T> using IteratorHelper_t = typename IteratorHelper<dim, T>::type; } // namespace /* -------------------------------------------------------------------------- */ template <typename T, bool is_scal> class Array : public ArrayBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using value_type = T; using reference = value_type &; using pointer_type = value_type *; using const_reference = const value_type &; /// Allocation of a new vector explicit inline Array(UInt size = 0, UInt nb_component = 1, const ID & id = ""); /// Allocation of a new vector with a default value Array(UInt size, UInt nb_component, const value_type def_values[], const ID & id = ""); /// Allocation of a new vector with a default value Array(UInt size, UInt nb_component, const_reference value, const ID & id = ""); /// Copy constructor (deep copy if deep=true) Array(const Array<value_type, is_scal> & vect, bool deep = true, const ID & id = ""); #ifndef SWIG /// Copy constructor (deep copy) explicit Array(const std::vector<value_type> & vect); #endif inline ~Array() override; Array & operator=(const Array & a) { /// this is to let STL allocate and copy arrays in the case of /// std::vector::resize AKANTU_DEBUG_ASSERT(this->size_ == 0, "Cannot copy akantu::Array"); return const_cast<Array &>(a); } #ifndef SWIG /* ------------------------------------------------------------------------ */ /* Iterator */ /* ------------------------------------------------------------------------ */ /// \todo protected: does not compile with intel check why public: template <class R, class it, class IR = R, bool is_tensor_ = is_tensor<R>::value> class iterator_internal; public: /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ template <typename R = T> class const_iterator; template <typename R = T> class iterator; /* ------------------------------------------------------------------------ */ /// iterator for Array of nb_component = 1 using scalar_iterator = iterator<T>; /// const_iterator for Array of nb_component = 1 using const_scalar_iterator = const_iterator<T>; /// iterator returning Vectors of size n on entries of Array with /// nb_component = n using vector_iterator = iterator<Vector<T>>; /// const_iterator returning Vectors of n size on entries of Array with /// nb_component = n using const_vector_iterator = const_iterator<Vector<T>>; /// iterator returning Matrices of size (m, n) on entries of Array with /// nb_component = m*n using matrix_iterator = iterator<Matrix<T>>; /// const iterator returning Matrices of size (m, n) on entries of Array with /// nb_component = m*n using const_matrix_iterator = const_iterator<Matrix<T>>; /// iterator returning Tensor3 of size (m, n, k) on entries of Array with /// nb_component = m*n*k using tensor3_iterator = iterator<Tensor3<T>>; /// const iterator returning Tensor3 of size (m, n, k) on entries of Array /// with nb_component = m*n*k using const_tensor3_iterator = const_iterator<Tensor3<T>>; /* ------------------------------------------------------------------------ */ template <typename... Ns> inline decltype(auto) begin(Ns &&... n); template <typename... Ns> inline decltype(auto) end(Ns &&... n); template <typename... Ns> inline decltype(auto) begin(Ns &&... n) const; template <typename... Ns> inline decltype(auto) end(Ns &&... n) const; template <typename... Ns> inline decltype(auto) begin_reinterpret(Ns &&... n); template <typename... Ns> inline decltype(auto) end_reinterpret(Ns &&... n); template <typename... Ns> inline decltype(auto) begin_reinterpret(Ns &&... n) const; template <typename... Ns> inline decltype(auto) end_reinterpret(Ns &&... n) const; #endif // SWIG /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// append a tuple of size nb_component containing value inline void push_back(const_reference value); /// append a vector // inline void push_back(const value_type new_elem[]); #ifndef SWIG /// append a Vector or a Matrix template <template <typename> class C, typename = std::enable_if_t<is_tensor<C<T>>::value>> inline void push_back(const C<T> & new_elem); /// append the value of the iterator template <typename Ret> inline void push_back(const iterator<Ret> & it); /// erase the value at position i inline void erase(UInt i); /// ask Nico, clarify template <typename R> inline iterator<R> erase(const iterator<R> & it); #endif /// changes the allocated size but not the size virtual void reserve(UInt size); /// change the size of the Array virtual void resize(UInt size); /// change the size of the Array and initialize the values virtual void resize(UInt size, const T & val); /// change the number of components by interlacing data /// @param multiplicator number of interlaced components add /// @param block_size blocks of data in the array /// Examaple for block_size = 2, multiplicator = 2 /// array = oo oo oo -> new array = oo nn nn oo nn nn oo nn nn void extendComponentsInterlaced(UInt multiplicator, UInt stride); /// search elem in the vector, return the position of the first occurrence or /// -1 if not found UInt find(const_reference elem) const; /// @see Array::find(const_reference elem) const UInt find(T elem[]) const; #ifndef SWIG /// @see Array::find(const_reference elem) const template <template <typename> class C, typename = std::enable_if_t<is_tensor<C<T>>::value>> inline UInt find(const C<T> & elem); #endif /// set all entries of the array to 0 inline void clear() { std::fill_n(values, size_ * nb_component, T()); } /// set all entries of the array to the value t /// @param t value to fill the array with inline void set(T t) { std::fill_n(values, size_ * nb_component, t); } #ifndef SWIG /// set all tuples of the array to a given vector or matrix /// @param vm Matrix or Vector to fill the array with template <template <typename> class C, typename = std::enable_if_t<is_tensor<C<T>>::value>> inline void set(const C<T> & vm); #endif /// Append the content of the other array to the current one void append(const Array<T> & other); /// copy another Array in the current Array, the no_sanity_check allows you to /// force the copy in cases where you know what you do with two non matching /// Arrays in terms of n void copy(const Array<T, is_scal> & other, bool no_sanity_check = false); /// give the address of the memory allocated for this vector T * storage() const { return values; }; /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; protected: /// perform the allocation for the constructors void allocate(UInt size, UInt nb_component = 1); /// resize initializing with uninitialized_fill if fill is set void resizeUnitialized(UInt new_size, bool fill, const T & val = T()); /* ------------------------------------------------------------------------ */ /* Operators */ /* ------------------------------------------------------------------------ */ public: /// substraction entry-wise Array<T, is_scal> & operator-=(const Array<T, is_scal> & other); /// addition entry-wise Array<T, is_scal> & operator+=(const Array<T, is_scal> & other); /// multiply evry entry by alpha Array<T, is_scal> & operator*=(const T & alpha); /// check if the array are identical entry-wise bool operator==(const Array<T, is_scal> & other) const; /// @see Array::operator==(const Array<T, is_scal> & other) const bool operator!=(const Array<T, is_scal> & other) const; /// return a reference to the j-th entry of the i-th tuple inline reference operator()(UInt i, UInt j = 0); /// return a const reference to the j-th entry of the i-th tuple inline const_reference operator()(UInt i, UInt j = 0) const; /// return a reference to the ith component of the 1D array inline reference operator[](UInt i); /// return a const reference to the ith component of the 1D array inline const_reference operator[](UInt i) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// array of values T * values; // /!\ very dangerous }; /* -------------------------------------------------------------------------- */ /* Inline Functions Array<T, is_scal> */ /* -------------------------------------------------------------------------- */ template <typename T, bool is_scal> inline std::ostream & operator<<(std::ostream & stream, const Array<T, is_scal> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ /* Inline Functions ArrayBase */ /* -------------------------------------------------------------------------- */ inline std::ostream & operator<<(std::ostream & stream, const ArrayBase & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "aka_array_tmpl.hh" #include "aka_types.hh" #endif /* __AKANTU_VECTOR_HH__ */ diff --git a/src/common/aka_array_tmpl.hh b/src/common/aka_array_tmpl.hh index 624536626..e5145384e 100644 --- a/src/common/aka_array_tmpl.hh +++ b/src/common/aka_array_tmpl.hh @@ -1,1278 +1,1278 @@ /** * @file aka_array_tmpl.hh * + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jul 15 2010 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Inline functions of the classes Array<T> and ArrayBase * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* Inline Functions Array<T> */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" /* -------------------------------------------------------------------------- */ #include <memory> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_ARRAY_TMPL_HH__ #define __AKANTU_AKA_ARRAY_TMPL_HH__ namespace akantu { namespace debug { struct ArrayException : public Exception {}; } // namespace debug /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline T & Array<T, is_scal>::operator()(UInt i, UInt j) { AKANTU_DEBUG_ASSERT(size_ > 0, "The array \"" << id << "\" is empty"); AKANTU_DEBUG_ASSERT((i < size_) && (j < nb_component), "The value at position [" << i << "," << j << "] is out of range in array \"" << id << "\""); return values[i * nb_component + j]; } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline const T & Array<T, is_scal>::operator()(UInt i, UInt j) const { AKANTU_DEBUG_ASSERT(size_ > 0, "The array \"" << id << "\" is empty"); AKANTU_DEBUG_ASSERT((i < size_) && (j < nb_component), "The value at position [" << i << "," << j << "] is out of range in array \"" << id << "\""); return values[i * nb_component + j]; } template <class T, bool is_scal> inline T & Array<T, is_scal>::operator[](UInt i) { AKANTU_DEBUG_ASSERT(size_ > 0, "The array \"" << id << "\" is empty"); AKANTU_DEBUG_ASSERT((i < size_ * nb_component), "The value at position [" << i << "] is out of range in array \"" << id << "\""); return values[i]; } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline const T & Array<T, is_scal>::operator[](UInt i) const { AKANTU_DEBUG_ASSERT(size_ > 0, "The array \"" << id << "\" is empty"); AKANTU_DEBUG_ASSERT((i < size_ * nb_component), "The value at position [" << i << "] is out of range in array \"" << id << "\""); return values[i]; } /* -------------------------------------------------------------------------- */ /** * append a tuple to the array with the value value for all components * @param value the new last tuple or the array will contain nb_component copies * of value */ template <class T, bool is_scal> inline void Array<T, is_scal>::push_back(const T & value) { resizeUnitialized(size_ + 1, true, value); } /* -------------------------------------------------------------------------- */ /** * append a tuple to the array * @param new_elem a C-array containing the values to be copied to the end of * the array */ // template <class T, bool is_scal> // inline void Array<T, is_scal>::push_back(const T new_elem[]) { // UInt pos = size_; // resizeUnitialized(size_ + 1, false); // T * tmp = values + nb_component * pos; // std::uninitialized_copy(new_elem, new_elem + nb_component, tmp); // } /* -------------------------------------------------------------------------- */ #ifndef SWIG /** * append a matrix or a vector to the array * @param new_elem a reference to a Matrix<T> or Vector<T> */ template <class T, bool is_scal> template <template <typename> class C, typename> inline void Array<T, is_scal>::push_back(const C<T> & new_elem) { AKANTU_DEBUG_ASSERT( nb_component == new_elem.size(), "The vector(" << new_elem.size() << ") as not a size compatible with the Array (nb_component=" << nb_component << ")."); UInt pos = size_; resizeUnitialized(size_ + 1, false); T * tmp = values + nb_component * pos; std::uninitialized_copy(new_elem.storage(), new_elem.storage() + nb_component, tmp); } /* -------------------------------------------------------------------------- */ /** * append a tuple to the array * @param it an iterator to the tuple to be copied to the end of the array */ template <class T, bool is_scal> template <class Ret> inline void Array<T, is_scal>::push_back(const Array<T, is_scal>::iterator<Ret> & it) { UInt pos = size_; resizeUnitialized(size_ + 1, false); T * tmp = values + nb_component * pos; T * new_elem = it.data(); std::uninitialized_copy(new_elem, new_elem + nb_component, tmp); } #endif /* -------------------------------------------------------------------------- */ /** * erase an element. If the erased element is not the last of the array, the * last element is moved into the hole in order to maintain contiguity. This * may invalidate existing iterators (For instance an iterator obtained by * Array::end() is no longer correct) and will change the order of the * elements. * @param i index of element to erase */ template <class T, bool is_scal> inline void Array<T, is_scal>::erase(UInt i) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT((size_ > 0), "The array is empty"); AKANTU_DEBUG_ASSERT((i < size_), "The element at position [" << i << "] is out of range (" << i << ">=" << size_ << ")"); if (i != (size_ - 1)) { for (UInt j = 0; j < nb_component; ++j) { values[i * nb_component + j] = values[(size_ - 1) * nb_component + j]; } } resize(size_ - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Subtract another array entry by entry from this array in place. Both arrays * must * have the same size and nb_component. If the arrays have different shapes, * code compiled in debug mode will throw an expeption and optimised code * will behave in an unpredicted manner * @param other array to subtract from this * @return reference to modified this */ template <class T, bool is_scal> Array<T, is_scal> & Array<T, is_scal>:: operator-=(const Array<T, is_scal> & vect) { AKANTU_DEBUG_ASSERT((size_ == vect.size_) && (nb_component == vect.nb_component), "The too array don't have the same sizes"); T * a = values; T * b = vect.storage(); for (UInt i = 0; i < size_ * nb_component; ++i) { *a -= *b; ++a; ++b; } return *this; } /* -------------------------------------------------------------------------- */ /** * Add another array entry by entry to this array in place. Both arrays must * have the same size and nb_component. If the arrays have different shapes, * code compiled in debug mode will throw an expeption and optimised code * will behave in an unpredicted manner * @param other array to add to this * @return reference to modified this */ template <class T, bool is_scal> Array<T, is_scal> & Array<T, is_scal>:: operator+=(const Array<T, is_scal> & vect) { AKANTU_DEBUG_ASSERT((size_ == vect.size()) && (nb_component == vect.nb_component), "The too array don't have the same sizes"); T * a = values; T * b = vect.storage(); for (UInt i = 0; i < size_ * nb_component; ++i) { *a++ += *b++; } return *this; } /* -------------------------------------------------------------------------- */ /** * Multiply all entries of this array by a scalar in place * @param alpha scalar multiplicant * @return reference to modified this */ #ifndef SWIG template <class T, bool is_scal> Array<T, is_scal> & Array<T, is_scal>::operator*=(const T & alpha) { T * a = values; for (UInt i = 0; i < size_ * nb_component; ++i) { *a++ *= alpha; } return *this; } #endif /* -------------------------------------------------------------------------- */ /** * Compare this array element by element to another. * @param other array to compare to * @return true it all element are equal and arrays have the same shape, else * false */ template <class T, bool is_scal> bool Array<T, is_scal>::operator==(const Array<T, is_scal> & array) const { bool equal = nb_component == array.nb_component && size_ == array.size_ && id == array.id; if (!equal) return false; if (values == array.storage()) return true; else return std::equal(values, values + size_ * nb_component, array.storage()); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> bool Array<T, is_scal>::operator!=(const Array<T, is_scal> & array) const { return !operator==(array); } /* -------------------------------------------------------------------------- */ #ifndef SWIG /** * set all tuples of the array to a given vector or matrix * @param vm Matrix or Vector to fill the array with */ template <class T, bool is_scal> template <template <typename> class C, typename> inline void Array<T, is_scal>::set(const C<T> & vm) { AKANTU_DEBUG_ASSERT( nb_component == vm.size(), "The size of the object does not match the number of components"); for (T * it = values; it < values + nb_component * size_; it += nb_component) { std::copy(vm.storage(), vm.storage() + nb_component, it); } } #endif /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Array<T, is_scal>::append(const Array<T> & other) { AKANTU_DEBUG_ASSERT( nb_component == other.nb_component, "Cannot append an array with a different number of component"); UInt old_size = this->size_; this->resizeUnitialized(this->size_ + other.size(), false); T * tmp = values + nb_component * old_size; std::uninitialized_copy(other.storage(), other.storage() + other.size() * nb_component, tmp); } /* -------------------------------------------------------------------------- */ /* Functions Array<T, is_scal> */ /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Array<T, is_scal>::Array(UInt size, UInt nb_component, const ID & id) : ArrayBase(id), values(nullptr) { AKANTU_DEBUG_IN(); allocate(size, nb_component); if (!is_scal) { T val = T(); std::uninitialized_fill(values, values + size * nb_component, val); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Array<T, is_scal>::Array(UInt size, UInt nb_component, const T def_values[], const ID & id) : ArrayBase(id), values(NULL) { AKANTU_DEBUG_IN(); allocate(size, nb_component); T * tmp = values; for (UInt i = 0; i < size; ++i) { tmp = values + nb_component * i; std::uninitialized_copy(def_values, def_values + nb_component, tmp); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Array<T, is_scal>::Array(UInt size, UInt nb_component, const T & value, const ID & id) : ArrayBase(id), values(nullptr) { AKANTU_DEBUG_IN(); allocate(size, nb_component); std::uninitialized_fill_n(values, size * nb_component, value); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Array<T, is_scal>::Array(const Array<T, is_scal> & vect, bool deep, const ID & id) : ArrayBase(vect) { AKANTU_DEBUG_IN(); this->id = (id == "") ? vect.id : id; if (deep) { allocate(vect.size_, vect.nb_component); T * tmp = values; std::uninitialized_copy(vect.storage(), vect.storage() + size_ * nb_component, tmp); } else { this->values = vect.storage(); this->size_ = vect.size_; this->nb_component = vect.nb_component; this->allocated_size = vect.allocated_size; this->size_of_type = vect.size_of_type; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #ifndef SWIG template <class T, bool is_scal> Array<T, is_scal>::Array(const std::vector<T> & vect) { AKANTU_DEBUG_IN(); this->id = ""; allocate(vect.size(), 1); T * tmp = values; std::uninitialized_copy(&(vect[0]), &(vect[size_ - 1]), tmp); AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Array<T, is_scal>::~Array() { AKANTU_DEBUG_IN(); AKANTU_DEBUG(dblAccessory, "Freeing " << printMemorySize<T>(allocated_size * nb_component) << " (" << id << ")"); if (values) { if (!is_scal) for (UInt i = 0; i < size_ * nb_component; ++i) { T * obj = values + i; obj->~T(); } free(values); } size_ = allocated_size = 0; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * perform the allocation for the constructors * @param size is the size of the array * @param nb_component is the number of component of the array */ template <class T, bool is_scal> void Array<T, is_scal>::allocate(UInt size, UInt nb_component) { AKANTU_DEBUG_IN(); if (size == 0) { values = nullptr; } else { values = static_cast<T *>(malloc(nb_component * size * sizeof(T))); AKANTU_DEBUG_ASSERT(values != nullptr, "Cannot allocate " << printMemorySize<T>(size * nb_component) << " (" << id << ")"); } if (values == nullptr) { this->size_ = this->allocated_size = 0; } else { AKANTU_DEBUG(dblAccessory, "Allocated " << printMemorySize<T>(size * nb_component) << " (" << id << ")"); this->size_ = this->allocated_size = size; } this->size_of_type = sizeof(T); this->nb_component = nb_component; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Array<T, is_scal>::reserve(UInt new_size) { UInt tmp_size = this->size_; resizeUnitialized(new_size, false); this->size_ = tmp_size; } /* -------------------------------------------------------------------------- */ /** * change the size of the array and allocate or free memory if needed. If the * size increases, the new tuples are filled with zeros * @param new_size new number of tuples contained in the array */ template <class T, bool is_scal> void Array<T, is_scal>::resize(UInt new_size) { resizeUnitialized(new_size, !is_scal); } /* -------------------------------------------------------------------------- */ /** * change the size of the array and allocate or free memory if needed. If the * size increases, the new tuples are filled with zeros * @param new_size new number of tuples contained in the array */ template <class T, bool is_scal> void Array<T, is_scal>::resize(UInt new_size, const T & val) { this->resizeUnitialized(new_size, true, val); } /* -------------------------------------------------------------------------- */ /** * change the size of the array and allocate or free memory if needed. * @param new_size new number of tuples contained in the array */ template <class T, bool is_scal> void Array<T, is_scal>::resizeUnitialized(UInt new_size, bool fill, const T & val) { // AKANTU_DEBUG_IN(); // free some memory if (new_size <= allocated_size) { if (!is_scal) { T * old_values = values; if (new_size < size_) { for (UInt i = new_size * nb_component; i < size_ * nb_component; ++i) { T * obj = old_values + i; obj->~T(); } } } if (allocated_size - new_size > AKANTU_MIN_ALLOCATION) { AKANTU_DEBUG(dblAccessory, "Freeing " << printMemorySize<T>((allocated_size - size_) * nb_component) << " (" << id << ")"); // Normally there are no allocation problem when reducing an array if (new_size == 0) { free(values); values = nullptr; } else { auto * tmp_ptr = static_cast<T *>( realloc(values, new_size * nb_component * sizeof(T))); if (tmp_ptr == nullptr) { AKANTU_EXCEPTION("Cannot free data (" << id << ")" << " [current allocated size : " << allocated_size << " | " << "requested size : " << new_size << "]"); } values = tmp_ptr; } allocated_size = new_size; } } else { // allocate more memory UInt size_to_alloc = (new_size - allocated_size < AKANTU_MIN_ALLOCATION) ? allocated_size + AKANTU_MIN_ALLOCATION : new_size; auto * tmp_ptr = static_cast<T *>( realloc(values, size_to_alloc * nb_component * sizeof(T))); AKANTU_DEBUG_ASSERT( tmp_ptr != nullptr, "Cannot allocate " << printMemorySize<T>(size_to_alloc * nb_component)); if (tmp_ptr == nullptr) { AKANTU_ERROR("Cannot allocate more data (" << id << ")" << " [current allocated size : " << allocated_size << " | " << "requested size : " << new_size << "]"); } AKANTU_DEBUG(dblAccessory, "Allocating " << printMemorySize<T>( (size_to_alloc - allocated_size) * nb_component)); allocated_size = size_to_alloc; values = tmp_ptr; } if (fill && this->size_ < new_size) { std::uninitialized_fill(values + size_ * nb_component, values + new_size * nb_component, val); } size_ = new_size; // AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * change the number of components by interlacing data * @param multiplicator number of interlaced components add * @param block_size blocks of data in the array * Examaple for block_size = 2, multiplicator = 2 * array = oo oo oo -> new array = oo nn nn oo nn nn oo nn nn */ template <class T, bool is_scal> void Array<T, is_scal>::extendComponentsInterlaced(UInt multiplicator, UInt block_size) { AKANTU_DEBUG_IN(); if (multiplicator == 1) return; AKANTU_DEBUG_ASSERT(multiplicator > 1, "invalid multiplicator"); AKANTU_DEBUG_ASSERT(nb_component % block_size == 0, "stride must divide actual number of components"); values = static_cast<T *>( realloc(values, nb_component * multiplicator * size_ * sizeof(T))); UInt new_component = nb_component / block_size * multiplicator; for (UInt i = 0, k = size_ - 1; i < size_; ++i, --k) { for (UInt j = 0; j < new_component; ++j) { UInt m = new_component - j - 1; UInt n = m / multiplicator; for (UInt l = 0, p = block_size - 1; l < block_size; ++l, --p) { values[k * nb_component * multiplicator + m * block_size + p] = values[k * nb_component + n * block_size + p]; } } } nb_component = nb_component * multiplicator; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * search elem in the array, return the position of the first occurrence or * -1 if not found * @param elem the element to look for * @return index of the first occurrence of elem or -1 if elem is not present */ template <class T, bool is_scal> UInt Array<T, is_scal>::find(const T & elem) const { AKANTU_DEBUG_IN(); auto begin = this->begin(); auto end = this->end(); auto it = std::find(begin, end, elem); AKANTU_DEBUG_OUT(); return (it != end) ? it - begin : UInt(-1); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> UInt Array<T, is_scal>::find(T elem[]) const { AKANTU_DEBUG_IN(); T * it = values; UInt i = 0; for (; i < size_; ++i) { if (*it == elem[0]) { T * cit = it; UInt c = 0; for (; (c < nb_component) && (*cit == elem[c]); ++c, ++cit) ; if (c == nb_component) { AKANTU_DEBUG_OUT(); return i; } } it += nb_component; } return UInt(-1); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template <template <typename> class C, typename> inline UInt Array<T, is_scal>::find(const C<T> & elem) { AKANTU_DEBUG_ASSERT(elem.size() == nb_component, "Cannot find an element with a wrong size (" << elem.size() << ") != " << nb_component); return this->find(elem.storage()); } /* -------------------------------------------------------------------------- */ /** * copy the content of another array. This overwrites the current content. * @param other Array to copy into this array. It has to have the same * nb_component as this. If compiled in debug mode, an incorrect other will * result in an exception being thrown. Optimised code may result in * unpredicted behaviour. */ template <class T, bool is_scal> void Array<T, is_scal>::copy(const Array<T, is_scal> & vect, bool no_sanity_check) { AKANTU_DEBUG_IN(); if (!no_sanity_check) if (vect.nb_component != nb_component) AKANTU_ERROR("The two arrays do not have the same number of components"); resize((vect.size_ * vect.nb_component) / nb_component); T * tmp = values; std::uninitialized_copy(vect.storage(), vect.storage() + size_ * nb_component, tmp); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool is_scal> class ArrayPrintHelper { public: template <typename T> static void print_content(const Array<T> & vect, std::ostream & stream, int indent) { if (AKANTU_DEBUG_TEST(dblDump) || AKANTU_DEBUG_LEVEL_IS_TEST()) { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << " + values : {"; for (UInt i = 0; i < vect.size(); ++i) { stream << "{"; for (UInt j = 0; j < vect.getNbComponent(); ++j) { stream << vect(i, j); if (j != vect.getNbComponent() - 1) stream << ", "; } stream << "}"; if (i != vect.size() - 1) stream << ", "; } stream << "}" << std::endl; } } }; template <> class ArrayPrintHelper<false> { public: template <typename T> static void print_content(__attribute__((unused)) const Array<T> & vect, __attribute__((unused)) std::ostream & stream, __attribute__((unused)) int indent) {} }; /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Array<T, is_scal>::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; std::streamsize prec = stream.precision(); std::ios_base::fmtflags ff = stream.flags(); stream.setf(std::ios_base::showbase); stream.precision(2); stream << space << "Array<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; stream << space << " + id : " << this->id << std::endl; stream << space << " + size : " << this->size_ << std::endl; stream << space << " + nb_component : " << this->nb_component << std::endl; stream << space << " + allocated size : " << this->allocated_size << std::endl; stream << space << " + memory size : " << printMemorySize<T>(allocated_size * nb_component) << std::endl; if (!AKANTU_DEBUG_LEVEL_IS_TEST()) stream << space << " + address : " << std::hex << this->values << std::dec << std::endl; stream.precision(prec); stream.flags(ff); ArrayPrintHelper<is_scal>::print_content(*this, stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /* Inline Functions ArrayBase */ /* -------------------------------------------------------------------------- */ inline UInt ArrayBase::getMemorySize() const { return allocated_size * nb_component * size_of_type; } inline void ArrayBase::empty() { size_ = 0; } #ifndef SWIG /* -------------------------------------------------------------------------- */ /* Iterators */ /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template <class R, class daughter, class IR, bool is_tensor> class Array<T, is_scal>::iterator_internal { public: using value_type = R; using pointer = R *; using reference = R &; using proxy = typename R::proxy; using const_proxy = const typename R::proxy; using const_reference = const R &; using internal_value_type = IR; using internal_pointer = IR *; using difference_type = std::ptrdiff_t; using iterator_category = std::random_access_iterator_tag; public: iterator_internal() = default; iterator_internal(pointer_type data, UInt _offset) : _offset(_offset), initial(data), ret(nullptr), ret_ptr(data) { AKANTU_ERROR( "The constructor should never be called it is just an ugly trick..."); } iterator_internal(std::unique_ptr<internal_value_type> && wrapped) : _offset(wrapped->size()), initial(wrapped->storage()), ret(std::move(wrapped)), ret_ptr(ret->storage()) {} iterator_internal(const iterator_internal & it) { if (this != &it) { this->_offset = it._offset; this->initial = it.initial; this->ret_ptr = it.ret_ptr; this->ret = std::make_unique<internal_value_type>(*it.ret, false); } } iterator_internal(iterator_internal && it) = default; virtual ~iterator_internal() = default; inline iterator_internal & operator=(const iterator_internal & it) { if (this != &it) { this->_offset = it._offset; this->initial = it.initial; this->ret_ptr = it.ret_ptr; if (this->ret) this->ret->shallowCopy(*it.ret); else this->ret = std::make_unique<internal_value_type>(*it.ret, false); } return *this; } UInt getCurrentIndex() { return (this->ret_ptr - this->initial) / this->_offset; }; inline reference operator*() { ret->values = ret_ptr; return *ret; }; inline const_reference operator*() const { ret->values = ret_ptr; return *ret; }; inline pointer operator->() { ret->values = ret_ptr; return ret.get(); }; inline daughter & operator++() { ret_ptr += _offset; return static_cast<daughter &>(*this); }; inline daughter & operator--() { ret_ptr -= _offset; return static_cast<daughter &>(*this); }; inline daughter & operator+=(const UInt n) { ret_ptr += _offset * n; return static_cast<daughter &>(*this); } inline daughter & operator-=(const UInt n) { ret_ptr -= _offset * n; return static_cast<daughter &>(*this); } inline proxy operator[](const UInt n) { ret->values = ret_ptr + n * _offset; return proxy(*ret); } inline const_proxy operator[](const UInt n) const { ret->values = ret_ptr + n * _offset; return const_proxy(*ret); } inline bool operator==(const iterator_internal & other) const { return this->ret_ptr == other.ret_ptr; } inline bool operator!=(const iterator_internal & other) const { return this->ret_ptr != other.ret_ptr; } inline bool operator<(const iterator_internal & other) const { return this->ret_ptr < other.ret_ptr; } inline bool operator<=(const iterator_internal & other) const { return this->ret_ptr <= other.ret_ptr; } inline bool operator>(const iterator_internal & other) const { return this->ret_ptr > other.ret_ptr; } inline bool operator>=(const iterator_internal & other) const { return this->ret_ptr >= other.ret_ptr; } inline daughter operator+(difference_type n) { daughter tmp(static_cast<daughter &>(*this)); tmp += n; return tmp; } inline daughter operator-(difference_type n) { daughter tmp(static_cast<daughter &>(*this)); tmp -= n; return tmp; } inline difference_type operator-(const iterator_internal & b) { return (this->ret_ptr - b.ret_ptr) / _offset; } inline pointer_type data() const { return ret_ptr; } inline difference_type offset() const { return _offset; } protected: UInt _offset{0}; pointer_type initial{nullptr}; std::unique_ptr<internal_value_type> ret{nullptr}; pointer_type ret_ptr{nullptr}; }; /* -------------------------------------------------------------------------- */ /** * Specialization for scalar types */ template <class T, bool is_scal> template <class R, class daughter, class IR> class Array<T, is_scal>::iterator_internal<R, daughter, IR, false> { public: using value_type = R; using pointer = R *; using reference = R &; using const_reference = const R &; using internal_value_type = IR; using internal_pointer = IR *; using difference_type = std::ptrdiff_t; using iterator_category = std::random_access_iterator_tag; public: iterator_internal(pointer data = nullptr) : ret(data), initial(data){}; iterator_internal(const iterator_internal & it) = default; iterator_internal(iterator_internal && it) = default; virtual ~iterator_internal() = default; inline iterator_internal & operator=(const iterator_internal & it) = default; UInt getCurrentIndex() { return (this->ret - this->initial); }; inline reference operator*() { return *ret; }; inline const_reference operator*() const { return *ret; }; inline pointer operator->() { return ret; }; inline daughter & operator++() { ++ret; return static_cast<daughter &>(*this); }; inline daughter & operator--() { --ret; return static_cast<daughter &>(*this); }; inline daughter & operator+=(const UInt n) { ret += n; return static_cast<daughter &>(*this); } inline daughter & operator-=(const UInt n) { ret -= n; return static_cast<daughter &>(*this); } inline reference operator[](const UInt n) { return ret[n]; } inline bool operator==(const iterator_internal & other) const { return ret == other.ret; } inline bool operator!=(const iterator_internal & other) const { return ret != other.ret; } inline bool operator<(const iterator_internal & other) const { return ret < other.ret; } inline bool operator<=(const iterator_internal & other) const { return ret <= other.ret; } inline bool operator>(const iterator_internal & other) const { return ret > other.ret; } inline bool operator>=(const iterator_internal & other) const { return ret >= other.ret; } inline daughter operator-(difference_type n) { return daughter(ret - n); } inline daughter operator+(difference_type n) { return daughter(ret + n); } inline difference_type operator-(const iterator_internal & b) { return ret - b.ret; } inline pointer data() const { return ret; } protected: pointer ret{nullptr}; pointer initial{nullptr}; }; /* -------------------------------------------------------------------------- */ /* Begin/End functions implementation */ /* -------------------------------------------------------------------------- */ namespace detail { template <class Tuple, size_t... Is> constexpr auto take_front_impl(Tuple && t, std::index_sequence<Is...>) { return std::make_tuple(std::get<Is>(std::forward<Tuple>(t))...); } template <size_t N, class Tuple> constexpr auto take_front(Tuple && t) { return take_front_impl(std::forward<Tuple>(t), std::make_index_sequence<N>{}); } template <typename... V> constexpr auto product_all(V &&... v) { std::common_type_t<int, V...> result = 1; (void)std::initializer_list<int>{(result *= v, 0)...}; return result; } template <typename... T> std::string to_string_all(T &&... t) { if (sizeof...(T) == 0) return ""; std::stringstream ss; bool noComma = true; ss << "("; (void)std::initializer_list<bool>{ (ss << (noComma ? "" : ", ") << t, noComma = false)...}; ss << ")"; return ss.str(); } template <std::size_t N> struct InstantiationHelper { template <typename type, typename T, typename... Ns> static auto instantiate(T && data, Ns... ns) { return std::make_unique<type>(data, ns...); } }; template <> struct InstantiationHelper<0> { template <typename type, typename T> static auto instantiate(T && data) { return data; } }; template <typename Arr, typename T, typename... Ns> decltype(auto) get_iterator(Arr && array, T * data, Ns &&... ns) { using type = IteratorHelper_t<sizeof...(Ns) - 1, T>; using array_type = std::decay_t<Arr>; using iterator = std::conditional_t<std::is_const<std::remove_reference_t<Arr>>::value, typename array_type::template const_iterator<type>, typename array_type::template iterator<type>>; static_assert(sizeof...(Ns), "You should provide a least one size"); if (array.getNbComponent() * array.size() != product_all(std::forward<Ns>(ns)...)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::ArrayException(), "The iterator on " << debug::demangle(typeid(Arr).name()) << to_string_all(array.size(), array.getNbComponent()) << "is not compatible with the type " << debug::demangle(typeid(type).name()) << to_string_all(ns...)); } auto && wrapped = aka::apply( [&](auto... n) { return InstantiationHelper<sizeof...(n)>::template instantiate<type>( data, n...); }, take_front<sizeof...(Ns) - 1>(std::make_tuple(ns...))); return iterator(std::move(wrapped)); } } // namespace detail /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::begin(Ns &&... ns) { return detail::get_iterator(*this, values, std::forward<Ns>(ns)..., size_); } template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::end(Ns &&... ns) { return detail::get_iterator(*this, values + nb_component * size_, std::forward<Ns>(ns)..., size_); } template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::begin(Ns &&... ns) const { return detail::get_iterator(*this, values, std::forward<Ns>(ns)..., size_); } template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::end(Ns &&... ns) const { return detail::get_iterator(*this, values + nb_component * size_, std::forward<Ns>(ns)..., size_); } template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::begin_reinterpret(Ns &&... ns) { return detail::get_iterator(*this, values, std::forward<Ns>(ns)...); } template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::end_reinterpret(Ns &&... ns) { return detail::get_iterator( *this, values + detail::product_all(std::forward<Ns>(ns)...), std::forward<Ns>(ns)...); } template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::begin_reinterpret(Ns &&... ns) const { return detail::get_iterator(*this, values, std::forward<Ns>(ns)...); } template <class T, bool is_scal> template <typename... Ns> inline decltype(auto) Array<T, is_scal>::end_reinterpret(Ns &&... ns) const { return detail::get_iterator( *this, values + detail::product_all(std::forward<Ns>(ns)...), std::forward<Ns>(ns)...); } /* -------------------------------------------------------------------------- */ /* Views */ /* -------------------------------------------------------------------------- */ namespace detail { template <typename Array, typename... Ns> class ArrayView { using tuple = std::tuple<Ns...>; public: ArrayView(Array && array, Ns... ns) : array(std::forward<Array>(array)), sizes(std::move(ns)...) {} ArrayView(ArrayView && array_view) = default; ArrayView & operator=(const ArrayView & array_view) = default; ArrayView & operator=(ArrayView && array_view) = default; decltype(auto) begin() { return aka::apply( [&](auto &&... ns) { return array.begin_reinterpret(ns...); }, sizes); } decltype(auto) begin() const { return aka::apply( [&](auto &&... ns) { return array.begin_reinterpret(ns...); }, sizes); } decltype(auto) end() { return aka::apply( [&](auto &&... ns) { return array.end_reinterpret(ns...); }, sizes); } decltype(auto) end() const { return aka::apply( [&](auto &&... ns) { return array.end_reinterpret(ns...); }, sizes); } decltype(auto) size() const { return std::get<std::tuple_size<tuple>::value - 1>(sizes); } decltype(auto) dims() const { return std::tuple_size<tuple>::value - 1; } private: Array array; tuple sizes; }; } // namespace detail /* -------------------------------------------------------------------------- */ template <typename Array, typename... Ns> decltype(auto) make_view(Array && array, Ns... ns) { static_assert(aka::conjunction<std::is_integral<std::decay_t<Ns>>...>::value, "Ns should be integral types"); auto size = std::forward<decltype(array)>(array).size() * std::forward<decltype(array)>(array).getNbComponent() / detail::product_all(ns...); return detail::ArrayView<Array, std::common_type_t<size_t, Ns>..., std::common_type_t<size_t, decltype(size)>>( std::forward<Array>(array), std::move(ns)..., size); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template <typename R> class Array<T, is_scal>::const_iterator : public iterator_internal<const R, Array<T, is_scal>::const_iterator<R>, R> { public: using parent = iterator_internal<const R, const_iterator, R>; using value_type = typename parent::value_type; using pointer = typename parent::pointer; using reference = typename parent::reference; using difference_type = typename parent::difference_type; using iterator_category = typename parent::iterator_category; public: const_iterator() : parent(){}; // const_iterator(pointer_type data, UInt offset) : parent(data, offset) {} // const_iterator(pointer warped) : parent(warped) {} // const_iterator(const parent & it) : parent(it) {} const_iterator(const const_iterator & it) = default; const_iterator(const_iterator && it) = default; template <typename P, typename = std::enable_if_t<not is_tensor<P>::value>> const_iterator(P * data) : parent(data) {} template <typename UP_P, typename = std::enable_if_t<is_tensor<typename UP_P::element_type>::value>> const_iterator(UP_P && tensor) : parent(std::forward<UP_P>(tensor)) {} const_iterator & operator=(const const_iterator & it) = default; }; template <class T, class R, bool is_tensor_ = is_tensor<R>::value> struct ConstConverterIteratorHelper { using const_iterator = typename Array<T>::template const_iterator<R>; using iterator = typename Array<T>::template iterator<R>; static inline const_iterator convert(const iterator & it) { return const_iterator(std::unique_ptr<R>(new R(*it, false))); } }; template <class T, class R> struct ConstConverterIteratorHelper<T, R, false> { using const_iterator = typename Array<T>::template const_iterator<R>; using iterator = typename Array<T>::template iterator<R>; static inline const_iterator convert(const iterator & it) { return const_iterator(it.data()); } }; template <class T, bool is_scal> template <typename R> class Array<T, is_scal>::iterator : public iterator_internal<R, Array<T, is_scal>::iterator<R>> { public: using parent = iterator_internal<R, iterator>; using value_type = typename parent::value_type; using pointer = typename parent::pointer; using reference = typename parent::reference; using difference_type = typename parent::difference_type; using iterator_category = typename parent::iterator_category; public: iterator() : parent(){}; iterator(const iterator & it) = default; iterator(iterator && it) = default; template <typename P, typename = std::enable_if_t<not is_tensor<P>::value>> iterator(P * data) : parent(data) {} template <typename UP_P, typename = std::enable_if_t<is_tensor<typename UP_P::element_type>::value>> iterator(UP_P && tensor) : parent(std::forward<UP_P>(tensor)) {} iterator & operator=(const iterator & it) = default; operator const_iterator<R>() { return ConstConverterIteratorHelper<T, R>::convert(*this); } }; /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template <typename R> inline typename Array<T, is_scal>::template iterator<R> Array<T, is_scal>::erase(const iterator<R> & it) { T * curr = it.data(); UInt pos = (curr - values) / nb_component; erase(pos); iterator<R> rit = it; return --rit; } #endif } // namespace akantu #endif /* __AKANTU_AKA_ARRAY_TMPL_HH__ */ diff --git a/src/common/aka_blas_lapack.hh b/src/common/aka_blas_lapack.hh index 55ba9a8c4..76a244310 100644 --- a/src/common/aka_blas_lapack.hh +++ b/src/common/aka_blas_lapack.hh @@ -1,343 +1,343 @@ /** * @file aka_blas_lapack.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Mar 06 2013 - * @date last modification: Mon Jan 18 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Interface of the Fortran BLAS/LAPACK libraries * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_BLAS_LAPACK_HH__ #define __AKANTU_AKA_BLAS_LAPACK_HH__ /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_BLAS #include "aka_fortran_mangling.hh" extern "C" { /* ------------------------------------------------------------------------ */ /* Double precision */ /* ------------------------------------------------------------------------ */ // LEVEL 1 double AKA_FC_GLOBAL(ddot, DDOT)(int *, double *, int *, double *, int *); void AKA_FC_GLOBAL(daxpy, DAXPY)(int *, double *, double *, int *, double *, int *); // LEVEL 2 void AKA_FC_GLOBAL(dgemv, DGEMV)(char *, int *, int *, double *, double *, int *, double *, int *, double *, double *, int *); // LEVEL 3 void AKA_FC_GLOBAL(dgemm, DGEMM)(char *, char *, int *, int *, int *, double *, double *, int *, double *, int *, double *, double *, int *); /* ------------------------------------------------------------------------ */ /* Simple precision */ /* ------------------------------------------------------------------------ */ // LEVEL 1 float AKA_FC_GLOBAL(sdot, SDOT)(int *, float *, int *, float *, int *); void AKA_FC_GLOBAL(saxpy, SAXPY)(int *, float *, float *, int *, float *, int *); // LEVEL 2 void AKA_FC_GLOBAL(sgemv, SGEMV)(char *, int *, int *, float *, float *, int *, float *, int *, float *, float *, int *); // LEVEL 3 void AKA_FC_GLOBAL(sgemm, SGEMM)(char *, char *, int *, int *, int *, float *, float *, int *, float *, int *, float *, float *, int *); } #endif namespace akantu { #define AKANTU_WARNING_IGNORE_UNUSED_PARAMETER #include "aka_warning.hh" /// Wrapper around the S/DDOT BLAS function that returns the dot product of two /// vectors template <typename T> inline T aka_dot(int * n, T * x, int * incx, T * y, int * incy) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "BLAS in the compilation options!"); } /// Wrapper around the S/DAXPY BLAS function that computes \f$y := \alpha x + /// y\f$ template <typename T> inline void aka_axpy(int * n, T * alpha, T * x, int * incx, T * y, int * incy) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "BLAS in the compilation options!"); } /// Wrapper around the S/DGEMV BLAS function that computes matrix-vector product /// \f$y := \alpha A^{(T)}x + \beta y \f$ template <typename T> inline void aka_gemv(char * trans, int * m, int * n, T * alpha, T * a, int * lda, T * x, int * incx, T * beta, T * y, int * incy) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "BLAS in the compilation options!"); } /// Wrapper around the S/DGEMM BLAS function that computes the product of two /// matrices \f$C := \alpha A^{(T)} B^{(T)} + \beta C \f$ template <typename T> inline void aka_gemm(char * transa, char * transb, int * m, int * n, int * k, T * alpha, T * a, int * lda, T * b, int * ldb, T * beta, T * c, int * ldc) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "BLAS in the compilation options!"); } #if defined(AKANTU_USE_BLAS) template <> inline double aka_dot<double>(int * n, double * x, int * incx, double * y, int * incy) { return AKA_FC_GLOBAL(ddot, DDOT)(n, x, incx, y, incy); } template <> inline void aka_axpy(int * n, double * alpha, double * x, int * incx, double * y, int * incy) { return AKA_FC_GLOBAL(daxpy, DAXPY)(n, alpha, x, incx, y, incy); } template <> inline void aka_gemv<double>(char * trans, int * m, int * n, double * alpha, double * a, int * lda, double * x, int * incx, double * beta, double * y, int * incy) { return AKA_FC_GLOBAL(dgemv, DGEMV)(trans, m, n, alpha, a, lda, x, incx, beta, y, incy); } template <> inline void aka_gemm<double>(char * transa, char * transb, int * m, int * n, int * k, double * alpha, double * a, int * lda, double * b, int * ldb, double * beta, double * c, int * ldc) { AKA_FC_GLOBAL(dgemm, DGEMM) (transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <> inline float aka_dot<float>(int * n, float * x, int * incx, float * y, int * incy) { return AKA_FC_GLOBAL(sdot, SDOT)(n, x, incx, y, incy); } template <> inline void aka_axpy(int * n, float * alpha, float * x, int * incx, float * y, int * incy) { return AKA_FC_GLOBAL(daxpy, DAXPY)(n, alpha, x, incx, y, incy); } template <> inline void aka_gemv<float>(char * trans, int * m, int * n, float * alpha, float * a, int * lda, float * x, int * incx, float * beta, float * y, int * incy) { AKA_FC_GLOBAL(sgemv, SGEMV) (trans, m, n, alpha, a, lda, x, incx, beta, y, incy); } template <> inline void aka_gemm<float>(char * transa, char * transb, int * m, int * n, int * k, float * alpha, float * a, int * lda, float * b, int * ldb, float * beta, float * c, int * ldc) { AKA_FC_GLOBAL(sgemm, SGEMM) (transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc); } #endif } // akantu #ifdef AKANTU_USE_LAPACK #include "aka_fortran_mangling.hh" extern "C" { /* ------------------------------------------------------------------------ */ /* Double general matrix */ /* ------------------------------------------------------------------------ */ /// compute the eigenvalues/vectors void AKA_FC_GLOBAL(dgeev, DGEEV)(char * jobvl, char * jobvr, int * n, double * a, int * lda, double * wr, double * wi, double * vl, int * ldvl, double * vr, int * ldvr, double * work, int * lwork, int * info); /// LU decomposition of a general matrix void AKA_FC_GLOBAL(dgetrf, DGETRF)(int * m, int * n, double * a, int * lda, int * ipiv, int * info); /// generate inverse of a matrix given its LU decomposition void AKA_FC_GLOBAL(dgetri, DGETRI)(int * n, double * a, int * lda, int * ipiv, double * work, int * lwork, int * info); /// solving A x = b using a LU factorization void AKA_FC_GLOBAL(dgetrs, DGETRS)(char * trans, int * n, int * nrhs, double * A, int * lda, int * ipiv, double * b, int * ldb, int * info); /* ------------------------------------------------------------------------ */ /* Simple general matrix */ /* ------------------------------------------------------------------------ */ /// compute the eigenvalues/vectors void AKA_FC_GLOBAL(sgeev, SGEEV)(char * jobvl, char * jobvr, int * n, float * a, int * lda, float * wr, float * wi, float * vl, int * ldvl, float * vr, int * ldvr, float * work, int * lwork, int * info); /// LU decomposition of a general matrix void AKA_FC_GLOBAL(sgetrf, SGETRF)(int * m, int * n, float * a, int * lda, int * ipiv, int * info); /// generate inverse of a matrix given its LU decomposition void AKA_FC_GLOBAL(sgetri, SGETRI)(int * n, float * a, int * lda, int * ipiv, float * work, int * lwork, int * info); /// solving A x = b using a LU factorization void AKA_FC_GLOBAL(sgetrs, SGETRS)(char * trans, int * n, int * nrhs, float * A, int * lda, int * ipiv, float * b, int * ldb, int * info); } #endif // AKANTU_USE_LAPACK namespace akantu { /// Wrapper around the S/DGEEV BLAS function that computes the eigenvalues and /// eigenvectors of a matrix template <typename T> inline void aka_geev(char * jobvl, char * jobvr, int * n, T * a, int * lda, T * wr, T * wi, T * vl, int * ldvl, T * vr, int * ldvr, T * work, int * lwork, int * info) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "LAPACK in the compilation options!"); } /// Wrapper around the S/DGETRF BLAS function that computes the LU decomposition /// of a matrix template <typename T> inline void aka_getrf(int * m, int * n, T * a, int * lda, int * ipiv, int * info) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "LAPACK in the compilation options!"); } /// Wrapper around the S/DGETRI BLAS function that computes the inverse of a /// matrix given its LU decomposition template <typename T> inline void aka_getri(int * n, T * a, int * lda, int * ipiv, T * work, int * lwork, int * info) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "LAPACK in the compilation options!"); } /// Wrapper around the S/DGETRS BLAS function that solves \f$A^{(T)}x = b\f$ /// using LU decomposition template <typename T> inline void aka_getrs(char * trans, int * n, int * nrhs, T * A, int * lda, int * ipiv, T * b, int * ldb, int * info) { AKANTU_ERROR(debug::demangle(typeid(T).name()) << "is not a type recognized, or you didn't activated " "LAPACK in the compilation options!"); } #include "aka_warning_restore.hh" #ifdef AKANTU_USE_LAPACK template <> inline void aka_geev<double>(char * jobvl, char * jobvr, int * n, double * a, int * lda, double * wr, double * wi, double * vl, int * ldvl, double * vr, int * ldvr, double * work, int * lwork, int * info) { AKA_FC_GLOBAL(dgeev, DGEEV) (jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info); } template <> inline void aka_getrf<double>(int * m, int * n, double * a, int * lda, int * ipiv, int * info) { AKA_FC_GLOBAL(dgetrf, DGETRF)(m, n, a, lda, ipiv, info); } template <> inline void aka_getri<double>(int * n, double * a, int * lda, int * ipiv, double * work, int * lwork, int * info) { AKA_FC_GLOBAL(dgetri, DGETRI)(n, a, lda, ipiv, work, lwork, info); } template <> inline void aka_getrs<double>(char * trans, int * n, int * nrhs, double * A, int * lda, int * ipiv, double * b, int * ldb, int * info) { AKA_FC_GLOBAL(dgetrs, DGETRS)(trans, n, nrhs, A, lda, ipiv, b, ldb, info); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <> inline void aka_geev<float>(char * jobvl, char * jobvr, int * n, float * a, int * lda, float * wr, float * wi, float * vl, int * ldvl, float * vr, int * ldvr, float * work, int * lwork, int * info) { AKA_FC_GLOBAL(sgeev, SGEEV) (jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info); } template <> inline void aka_getrf<float>(int * m, int * n, float * a, int * lda, int * ipiv, int * info) { AKA_FC_GLOBAL(sgetrf, SGETRF)(m, n, a, lda, ipiv, info); } template <> inline void aka_getri<float>(int * n, float * a, int * lda, int * ipiv, float * work, int * lwork, int * info) { AKA_FC_GLOBAL(sgetri, SGETRI)(n, a, lda, ipiv, work, lwork, info); } template <> inline void aka_getrs<float>(char * trans, int * n, int * nrhs, float * A, int * lda, int * ipiv, float * b, int * ldb, int * info) { AKA_FC_GLOBAL(sgetrs, SGETRS)(trans, n, nrhs, A, lda, ipiv, b, ldb, info); } #endif } // akantu #endif /* __AKANTU_AKA_BLAS_LAPACK_HH__ */ diff --git a/src/common/aka_circular_array.hh b/src/common/aka_circular_array.hh index 7b9972b38..442967ff9 100644 --- a/src/common/aka_circular_array.hh +++ b/src/common/aka_circular_array.hh @@ -1,130 +1,129 @@ /** * @file aka_circular_array.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Sun Aug 13 2017 * * @brief class of circular array * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_CIRCULAR_ARRAY_HH__ #define __AKANTU_AKA_CIRCULAR_ARRAY_HH__ /* -------------------------------------------------------------------------- */ #include <typeinfo> /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" /* -------------------------------------------------------------------------- */ namespace akantu { template <class T> class CircularArray : protected Array<T> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef typename Array<T>::value_type value_type; typedef typename Array<T>::reference reference; typedef typename Array<T>::pointer_type pointer_type; typedef typename Array<T>::const_reference const_reference; /// Allocation of a new array with a default value CircularArray(UInt size, UInt nb_component = 1, const_reference value = value_type(), const ID & id = "") : Array<T>(size, nb_component, value, id), start_position(0), end_position(size - 1) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); }; virtual ~CircularArray() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /** advance start and end position by one: the first element is now at the end of the array **/ inline void makeStep(); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; private: /* ------------------------------------------------------------------------ */ /* Operators */ /* ------------------------------------------------------------------------ */ public: inline reference operator()(UInt i, UInt j = 0); inline const_reference operator()(UInt i, UInt j = 0) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: UInt size() const { return this->size_; }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// indice of first element in this circular array UInt start_position; /// indice of last element in this circular array UInt end_position; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_INCLUDE_INLINE_IMPL) #include "aka_circular_array_inline_impl.cc" #endif /// standard output stream operator template <typename T> inline std::ostream & operator<<(std::ostream & stream, const CircularArray<T> & _this) { _this.printself(stream); return stream; } } // akantu #endif /* __AKANTU_AKA_CIRCULAR_ARRAY_HH__ */ diff --git a/src/common/aka_circular_array_inline_impl.cc b/src/common/aka_circular_array_inline_impl.cc index 8ebf880dc..98be1e402 100644 --- a/src/common/aka_circular_array_inline_impl.cc +++ b/src/common/aka_circular_array_inline_impl.cc @@ -1,99 +1,98 @@ /** * @file aka_circular_array_inline_impl.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Fri Nov 11 2011 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Feb 03 2016 * * @brief implementation of circular array * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* Inline Functions Array<T> */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <class T> inline typename CircularArray<T>::reference CircularArray<T>:: operator()(UInt i, UInt j) { AKANTU_DEBUG_ASSERT(end_position != start_position, "The array \"" << this->id << "\" is empty"); AKANTU_DEBUG_ASSERT( (i < (end_position - start_position + this->allocated_size) % this->allocated_size + 1) && (j < this->nb_component), "The value at position [" << i << "," << j << "] is out of range in array \"" << this->id << "\""); return this->values[((i + start_position) % this->allocated_size) * this->nb_component + j]; } /* -------------------------------------------------------------------------- */ template <typename T> inline typename CircularArray<T>::const_reference CircularArray<T>:: operator()(UInt i, UInt j) const { AKANTU_DEBUG_ASSERT(end_position != start_position, "The array \"" << this->id << "\" is empty"); AKANTU_DEBUG_ASSERT( (i < (end_position - start_position + this->allocated_size) % this->allocated_size + 1) && (j < this->nb_component), "The value at position [" << i << "," << j << "] is out of range in array \"" << this->id << "\""); return this->values[((i + start_position) % this->allocated_size) * this->nb_component + j]; } /* -------------------------------------------------------------------------- */ template <class T> inline void CircularArray<T>::makeStep() { AKANTU_DEBUG_IN(); start_position = (start_position + 1) % this->allocated_size; end_position = (end_position + 1) % this->allocated_size; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T> void CircularArray<T>::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "CircularArray<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; stream << space << " + start_position : " << this->start_position << std::endl; stream << space << " + end_position : " << this->end_position << std::endl; Array<T>::printself(stream, indent + 1); stream << space << "]" << std::endl; } diff --git a/src/common/aka_common.cc b/src/common/aka_common.cc index 4449190bc..9faaab7c6 100644 --- a/src/common/aka_common.cc +++ b/src/common/aka_common.cc @@ -1,153 +1,152 @@ /** * @file aka_common.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Mon Feb 05 2018 * * @brief Initialization of global variables * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_random_generator.hh" #include "aka_static_memory.hh" #include "communicator.hh" #include "cppargparse.hh" #include "parser.hh" #include "communication_tag.hh" /* -------------------------------------------------------------------------- */ #include <ctime> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void initialize(int & argc, char **& argv) { AKANTU_DEBUG_IN(); initialize("", argc, argv); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void initialize(const std::string & input_file, int & argc, char **& argv) { AKANTU_DEBUG_IN(); StaticMemory::getStaticMemory(); Communicator & comm = Communicator::getStaticCommunicator(argc, argv); Tag::setMaxTag(comm.getMaxTag()); debug::debugger.setParallelContext(comm.whoAmI(), comm.getNbProc()); debug::setDebugLevel(dblError); static_argparser.setParallelContext(comm.whoAmI(), comm.getNbProc()); static_argparser.setExternalExitFunction(debug::exit); static_argparser.addArgument("--aka_input_file", "Akantu's input file", 1, cppargparse::_string, std::string()); static_argparser.addArgument( "--aka_debug_level", std::string("Akantu's overall debug level") + std::string(" (0: error, 1: exceptions, 4: warnings, 5: info, ..., " "100: dump") + std::string(" more info on levels can be foind in aka_error.hh)"), 1, cppargparse::_integer, int(dblWarning)); static_argparser.addArgument( "--aka_print_backtrace", "Should Akantu print a backtrace in case of error", 0, cppargparse::_boolean, false, true); static_argparser.parse(argc, argv, cppargparse::_remove_parsed); std::string infile = static_argparser["aka_input_file"]; if (infile == "") infile = input_file; debug::debugger.printBacktrace(static_argparser["aka_print_backtrace"]); if ("" != infile) { readInputFile(infile); } long int seed; try { seed = static_parser.getParameter("seed", _ppsc_current_scope); } catch (debug::Exception &) { seed = time(nullptr); } seed *= (comm.whoAmI() + 1); RandomGenerator<UInt>::seed(seed); int dbl_level = static_argparser["aka_debug_level"]; debug::setDebugLevel(DebugLevel(dbl_level)); AKANTU_DEBUG_INFO("Random seed set to " << seed); std::atexit(finalize); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void finalize() { AKANTU_DEBUG_IN(); // if (StaticCommunicator::isInstantiated()) { // StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); // delete &comm; // } if (StaticMemory::isInstantiated()) { delete &(StaticMemory::getStaticMemory()); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void readInputFile(const std::string & input_file) { static_parser.parse(input_file); } /* -------------------------------------------------------------------------- */ cppargparse::ArgumentParser & getStaticArgumentParser() { return static_argparser; } /* -------------------------------------------------------------------------- */ Parser & getStaticParser() { return static_parser; } /* -------------------------------------------------------------------------- */ const ParserSection & getUserParser() { return *(static_parser.getSubSections(ParserType::_user).first); } std::unique_ptr<Communicator> Communicator::static_communicator; } // akantu diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh index 09bcf4b14..37aaded5b 100644 --- a/src/common/aka_common.hh +++ b/src/common/aka_common.hh @@ -1,519 +1,519 @@ /** * @file aka_common.hh * + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Mon Feb 12 2018 * * @brief common type descriptions for akantu * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * All common things to be included in the projects files * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMON_HH__ #define __AKANTU_COMMON_HH__ #include "aka_compatibilty_with_cpp_standard.hh" /* -------------------------------------------------------------------------- */ #define __BEGIN_AKANTU_DUMPER__ namespace dumper { #define __END_AKANTU_DUMPER__ } /* -------------------------------------------------------------------------- */ #if defined(WIN32) #define __attribute__(x) #endif /* -------------------------------------------------------------------------- */ #include "aka_config.hh" #include "aka_error.hh" #include "aka_safe_enum.hh" /* -------------------------------------------------------------------------- */ #include <boost/preprocessor.hpp> #include <limits> #include <list> #include <string> #include <type_traits> #include <unordered_map> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* Common types */ /* -------------------------------------------------------------------------- */ using ID = std::string; #ifdef AKANTU_NDEBUG static const Real REAL_INIT_VALUE = Real(0.); #else static const Real REAL_INIT_VALUE = std::numeric_limits<Real>::quiet_NaN(); #endif /* -------------------------------------------------------------------------- */ /* Memory types */ /* -------------------------------------------------------------------------- */ using MemoryID = UInt; // using Surface = std::string; // using SurfacePair= std::pair<Surface, Surface>; // using SurfacePairList = std::list<SurfacePair>; /* -------------------------------------------------------------------------- */ extern const UInt _all_dimensions; #define AKANTU_PP_ENUM(s, data, i, elem) \ BOOST_PP_TUPLE_REM() \ elem BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(i, BOOST_PP_DEC(data))) } // namespace akantu #if (defined(__GNUC__) || defined(__GNUG__)) #define AKA_GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if AKA_GCC_VERSION < 60000 #define AKANTU_ENUM_HASH(type_name) \ namespace std { \ template <> struct hash<::akantu::type_name> { \ using argument_type = ::akantu::type_name; \ size_t operator()(const argument_type & e) const noexcept { \ auto ue = underlying_type_t<argument_type>(e); \ return uh(ue); \ } \ \ private: \ const hash<underlying_type_t<argument_type>> uh{}; \ }; \ } #else #define AKANTU_ENUM_HASH(type_name) #endif // AKA_GCC_VERSION #endif // GNU #include "aka_element_classes_info.hh" namespace akantu { #define AKANTU_PP_CAT(s, data, elem) BOOST_PP_CAT(data, elem) #define AKANTU_PP_TYPE_TO_STR(s, data, elem) \ ({BOOST_PP_CAT(data::_, elem), BOOST_PP_STRINGIZE(elem)}) #define AKANTU_PP_STR_TO_TYPE(s, data, elem) \ ({BOOST_PP_STRINGIZE(elem), BOOST_PP_CAT(data::_, elem)}) #define AKANTU_ENUM_DECLARE(type_name, list) \ enum class type_name { \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(AKANTU_PP_CAT, _, list)) \ }; #define AKANTU_ENUM_OUTPUT_STREAM(type_name, list) \ } \ AKANTU_ENUM_HASH(type_name) \ namespace aka { \ inline std::string to_string(const ::akantu::type_name & type) { \ static std::unordered_map<::akantu::type_name, std::string> convert{ \ BOOST_PP_SEQ_FOR_EACH_I( \ AKANTU_PP_ENUM, BOOST_PP_SEQ_SIZE(list), \ BOOST_PP_SEQ_TRANSFORM(AKANTU_PP_TYPE_TO_STR, \ ::akantu::type_name, list))}; \ return convert.at(type); \ } \ } \ namespace akantu { \ inline std::ostream & operator<<(std::ostream & stream, \ const type_name & type) { \ stream << aka::to_string(type); \ return stream; \ } #define AKANTU_ENUM_INPUT_STREAM(type_name, list) \ inline std::istream & operator>>(std::istream & stream, type_name & type) { \ std::string str; \ stream >> str; \ static std::unordered_map<std::string, type_name> convert{ \ BOOST_PP_SEQ_FOR_EACH_I( \ AKANTU_PP_ENUM, BOOST_PP_SEQ_SIZE(list), \ BOOST_PP_SEQ_TRANSFORM(AKANTU_PP_STR_TO_TYPE, type_name, list))}; \ type = convert.at(str); \ return stream; \ } /* -------------------------------------------------------------------------- */ /* Mesh/FEM/Model types */ /* -------------------------------------------------------------------------- */ /// small help to use names for directions enum SpacialDirection { _x = 0, _y = 1, _z = 2 }; /// enum MeshIOType type of mesh reader/writer enum MeshIOType { _miot_auto, ///< Auto guess of the reader to use based on the extension _miot_gmsh, ///< Gmsh files _miot_gmsh_struct, ///< Gsmh reader with reintpretation of elements has /// structures elements _miot_diana, ///< TNO Diana mesh format _miot_abaqus ///< Abaqus mesh format }; /// enum MeshEventHandlerPriority defines relative order of execution of events enum EventHandlerPriority { _ehp_highest = 0, _ehp_mesh = 5, _ehp_fe_engine = 9, _ehp_synchronizer = 10, _ehp_dof_manager = 20, _ehp_model = 94, _ehp_non_local_manager = 100, _ehp_lowest = 100 }; #ifndef SWIG // clang-format off #define AKANTU_MODEL_TYPES \ (model) \ (solid_mechanics_model) \ (solid_mechanics_model_cohesive) \ (heat_transfer_model) \ (structural_mechanics_model) \ (embedded_model) // clang-format on /// enum ModelType defines which type of physics is solved AKANTU_ENUM_DECLARE(ModelType, AKANTU_MODEL_TYPES) AKANTU_ENUM_OUTPUT_STREAM(ModelType, AKANTU_MODEL_TYPES) AKANTU_ENUM_INPUT_STREAM(ModelType, AKANTU_MODEL_TYPES) #else enum class ModelType { _model, _solid_mechanics_model, _solid_mechanics_model_cohesive, _heat_transfer_model, _structural_mechanics_model, _embedded_model }; #endif /// enum AnalysisMethod type of solving method used to solve the equation of /// motion enum AnalysisMethod { _static = 0, _implicit_dynamic = 1, _explicit_lumped_mass = 2, _explicit_lumped_capacity = 2, _explicit_consistent_mass = 3 }; /// enum DOFSupportType defines which kind of dof that can exists enum DOFSupportType { _dst_nodal, _dst_generic }; /// Type of non linear resolution available in akantu enum NonLinearSolverType { _nls_linear, ///< No non linear convergence loop _nls_newton_raphson, ///< Regular Newton-Raphson _nls_newton_raphson_modified, ///< Newton-Raphson with initial tangent _nls_lumped, ///< Case of lumped mass or equivalent matrix _nls_auto ///< This will take a default value that make sense in case of /// model::getNewSolver }; /// Define the node/dof type enum NodeType : Int { _nt_pure_gost = -3, _nt_master = -2, _nt_normal = -1 }; /// Type of time stepping solver enum TimeStepSolverType { _tsst_static, ///< Static solution _tsst_dynamic, ///< Dynamic solver _tsst_dynamic_lumped, ///< Dynamic solver with lumped mass _tsst_not_defined, ///< For not defined cases }; /// Type of integration scheme enum IntegrationSchemeType { _ist_pseudo_time, ///< Pseudo Time _ist_forward_euler, ///< GeneralizedTrapezoidal(0) _ist_trapezoidal_rule_1, ///< GeneralizedTrapezoidal(1/2) _ist_backward_euler, ///< GeneralizedTrapezoidal(1) _ist_central_difference, ///< NewmarkBeta(0, 1/2) _ist_fox_goodwin, ///< NewmarkBeta(1/6, 1/2) _ist_trapezoidal_rule_2, ///< NewmarkBeta(1/2, 1/2) _ist_linear_acceleration, ///< NewmarkBeta(1/3, 1/2) _ist_newmark_beta, ///< generic NewmarkBeta with user defined /// alpha and beta _ist_generalized_trapezoidal ///< generic GeneralizedTrapezoidal with user /// defined alpha }; /// enum SolveConvergenceCriteria different convergence criteria enum SolveConvergenceCriteria { _scc_residual, ///< Use residual to test the convergence _scc_solution, ///< Use solution to test the convergence _scc_residual_mass_wgh ///< Use residual weighted by inv. nodal mass to testb }; /// enum CohesiveMethod type of insertion of cohesive elements enum CohesiveMethod { _intrinsic, _extrinsic }; /// @enum SparseMatrixType type of sparse matrix used enum MatrixType { _unsymmetric, _symmetric, _mt_not_defined }; /* -------------------------------------------------------------------------- */ /* Ghosts handling */ /* -------------------------------------------------------------------------- */ /// @enum CommunicatorType type of communication method to use enum CommunicatorType { _communicator_mpi, _communicator_dummy }; /// @enum SynchronizationTag type of synchronizations enum SynchronizationTag { //--- Generic tags --- _gst_whatever, _gst_update, _gst_size, //--- SolidMechanicsModel tags --- _gst_smm_mass, ///< synchronization of the SolidMechanicsModel.mass _gst_smm_for_gradu, ///< synchronization of the /// SolidMechanicsModel.displacement _gst_smm_boundary, ///< synchronization of the boundary, forces, velocities /// and displacement _gst_smm_uv, ///< synchronization of the nodal velocities and displacement _gst_smm_res, ///< synchronization of the nodal residual _gst_smm_init_mat, ///< synchronization of the data to initialize materials _gst_smm_stress, ///< synchronization of the stresses to compute the internal /// forces _gst_smmc_facets, ///< synchronization of facet data to setup facet synch _gst_smmc_facets_conn, ///< synchronization of facet global connectivity _gst_smmc_facets_stress, ///< synchronization of facets' stress to setup facet /// synch _gst_smmc_damage, ///< synchronization of damage // --- GlobalIdsUpdater tags --- _gst_giu_global_conn, ///< synchronization of global connectivities // --- CohesiveElementInserter tags --- _gst_ce_groups, ///< synchronization of cohesive element insertion depending /// on facet groups // --- GroupManager tags --- _gst_gm_clusters, ///< synchronization of clusters // --- HeatTransfer tags --- _gst_htm_capacity, ///< synchronization of the nodal heat capacity _gst_htm_temperature, ///< synchronization of the nodal temperature _gst_htm_gradient_temperature, ///< synchronization of the element gradient /// temperature // --- LevelSet tags --- _gst_htm_phi, ///< synchronization of the nodal level set value phi _gst_htm_gradient_phi, ///< synchronization of the element gradient phi //--- Material non local --- _gst_mnl_for_average, ///< synchronization of data to average in non local /// material _gst_mnl_weight, ///< synchronization of data for the weight computations // --- NeighborhoodSynchronization tags --- _gst_nh_criterion, // --- General tags --- _gst_test, ///< Test tag _gst_user_1, ///< tag for user simulations _gst_user_2, ///< tag for user simulations _gst_material_id, ///< synchronization of the material ids _gst_for_dump, ///< everything that needs to be synch before dump // --- Contact & Friction --- _gst_cf_nodal, ///< synchronization of disp, velo, and current position _gst_cf_incr, ///< synchronization of increment // --- Solver tags --- _gst_solver_solution ///< synchronization of the solution obained with the /// PETSc solver }; /// standard output stream operator for SynchronizationTag inline std::ostream & operator<<(std::ostream & stream, SynchronizationTag type); /// @enum GhostType type of ghost enum GhostType { _not_ghost = 0, _ghost = 1, _casper // not used but a real cute ghost }; } #ifndef SWIG AKANTU_ENUM_HASH(GhostType) #endif namespace akantu { /* -------------------------------------------------------------------------- */ struct GhostType_def { using type = GhostType; static const type _begin_ = _not_ghost; static const type _end_ = _casper; }; using ghost_type_t = safe_enum<GhostType_def>; extern ghost_type_t ghost_types; /// standard output stream operator for GhostType inline std::ostream & operator<<(std::ostream & stream, GhostType type); /* -------------------------------------------------------------------------- */ /* Global defines */ /* -------------------------------------------------------------------------- */ #define AKANTU_MIN_ALLOCATION 2000 #define AKANTU_INDENT " " #define AKANTU_INCLUDE_INLINE_IMPL /* -------------------------------------------------------------------------- */ /* Type traits */ /* -------------------------------------------------------------------------- */ struct TensorTrait {}; /* -------------------------------------------------------------------------- */ template <typename T> using is_tensor = std::is_base_of<TensorTrait, T>; /* -------------------------------------------------------------------------- */ template <typename T> using is_scalar = std::is_arithmetic<T>; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #define AKANTU_SET_MACRO(name, variable, type) \ inline void set##name(type variable) { this->variable = variable; } #define AKANTU_GET_MACRO(name, variable, type) \ inline type get##name() const { return variable; } #define AKANTU_GET_MACRO_NOT_CONST(name, variable, type) \ inline type get##name() { return variable; } #define AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, support, con) \ inline con Array<type> & get##name( \ const support & el_type, const GhostType & ghost_type = _not_ghost) \ con { \ return variable(el_type, ghost_type); \ } #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType, ) #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType, const) #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType, ) #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE_CONST(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType, const) /* -------------------------------------------------------------------------- */ /// initialize the static part of akantu void initialize(int & argc, char **& argv); /// initialize the static part of akantu and read the global input_file void initialize(const std::string & input_file, int & argc, char **& argv); /* -------------------------------------------------------------------------- */ /// finilize correctly akantu and clean the memory void finalize(); /* -------------------------------------------------------------------------- */ /// Read an new input file void readInputFile(const std::string & input_file); /* -------------------------------------------------------------------------- */ /* * For intel compiler annoying remark */ // #if defined(__INTEL_COMPILER) // /// remark #981: operands are evaluated in unspecified order // #pragma warning(disable : 981) // /// remark #383: value copied to temporary, reference to temporary used // #pragma warning(disable : 383) // #endif // defined(__INTEL_COMPILER) /* -------------------------------------------------------------------------- */ /* string manipulation */ /* -------------------------------------------------------------------------- */ inline std::string to_lower(const std::string & str); /* -------------------------------------------------------------------------- */ inline std::string trim(const std::string & to_trim); /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /// give a string representation of the a human readable size in bit template <typename T> std::string printMemorySize(UInt size); /* -------------------------------------------------------------------------- */ } // namespace akantu #include "aka_fwd.hh" namespace akantu { /// get access to the internal argument parser cppargparse::ArgumentParser & getStaticArgumentParser(); /// get access to the internal input file parser Parser & getStaticParser(); /// get access to the user part of the internal input file parser const ParserSection & getUserParser(); } // namespace akantu #include "aka_common_inline_impl.cc" /* -------------------------------------------------------------------------- */ #if AKANTU_INTEGER_SIZE == 4 #define AKANTU_HASH_COMBINE_MAGIC_NUMBER 0x9e3779b9 #elif AKANTU_INTEGER_SIZE == 8 #define AKANTU_HASH_COMBINE_MAGIC_NUMBER 0x9e3779b97f4a7c13LL #endif namespace std { /** * Hashing function for pairs based on hash_combine from boost The magic number * is coming from the golden number @f[\phi = \frac{1 + \sqrt5}{2}@f] * @f[\frac{2^32}{\phi} = 0x9e3779b9@f] * http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine * http://burtleburtle.net/bob/hash/doobs.html */ template <typename a, typename b> struct hash<std::pair<a, b>> { hash() = default; size_t operator()(const std::pair<a, b> & p) const { size_t seed = ah(p.first); return bh(p.second) + AKANTU_HASH_COMBINE_MAGIC_NUMBER + (seed << 6) + (seed >> 2); } private: const hash<a> ah{}; const hash<b> bh{}; }; } // namespace std #endif /* __AKANTU_COMMON_HH__ */ diff --git a/src/common/aka_common_inline_impl.cc b/src/common/aka_common_inline_impl.cc index a16615d07..9f2a34849 100644 --- a/src/common/aka_common_inline_impl.cc +++ b/src/common/aka_common_inline_impl.cc @@ -1,459 +1,458 @@ /** * @file aka_common_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief inline implementations of common akantu type descriptions * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * All common things to be included in the projects files * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include <algorithm> #include <cctype> #include <iomanip> #include <iostream> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_COMMON_INLINE_IMPL_CC__ #define __AKANTU_AKA_COMMON_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ /// standard output stream operator for GhostType inline std::ostream & operator<<(std::ostream & stream, GhostType type) { switch (type) { case _not_ghost: stream << "not_ghost"; break; case _ghost: stream << "ghost"; break; case _casper: stream << "Casper the friendly ghost"; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for TimeStepSolverType inline std::ostream & operator<<(std::ostream & stream, const TimeStepSolverType & type) { switch (type) { case _tsst_static: stream << "static"; break; case _tsst_dynamic: stream << "dynamic"; break; case _tsst_dynamic_lumped: stream << "dynamic_lumped"; break; case _tsst_not_defined: stream << "not defined time step solver"; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard input stream operator for TimeStepSolverType inline std::istream & operator>>(std::istream & stream, TimeStepSolverType & type) { std::string str; stream >> str; if (str == "static") type = _tsst_static; else if (str == "dynamic") type = _tsst_dynamic; else if (str == "dynamic_lumped") type = _tsst_dynamic_lumped; else { AKANTU_ERROR("The type " << str << " is not a recognized TimeStepSolverType"); stream.setstate(std::ios::failbit); } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for NonLinearSolverType inline std::ostream & operator<<(std::ostream & stream, const NonLinearSolverType & type) { switch (type) { case _nls_linear: stream << "linear"; break; case _nls_newton_raphson: stream << "newton_raphson"; break; case _nls_newton_raphson_modified: stream << "newton_raphson_modified"; break; case _nls_lumped: stream << "lumped"; break; case _nls_auto: stream << "auto"; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard input stream operator for NonLinearSolverType inline std::istream & operator>>(std::istream & stream, NonLinearSolverType & type) { std::string str; stream >> str; if (str == "linear") type = _nls_linear; else if (str == "newton_raphson") type = _nls_newton_raphson; else if (str == "newton_raphson_modified") type = _nls_newton_raphson_modified; else if (str == "lumped") type = _nls_lumped; else if (str == "auto") type = _nls_auto; else type = _nls_auto; return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for IntegrationSchemeType inline std::ostream & operator<<(std::ostream & stream, const IntegrationSchemeType & type) { switch (type) { case _ist_pseudo_time: stream << "pseudo_time"; break; case _ist_forward_euler: stream << "forward_euler"; break; case _ist_trapezoidal_rule_1: stream << "trapezoidal_rule_1"; break; case _ist_backward_euler: stream << "backward_euler"; break; case _ist_central_difference: stream << "central_difference"; break; case _ist_fox_goodwin: stream << "fox_goodwin"; break; case _ist_trapezoidal_rule_2: stream << "trapezoidal_rule_2"; break; case _ist_linear_acceleration: stream << "linear_acceleration"; break; case _ist_newmark_beta: stream << "newmark_beta"; break; case _ist_generalized_trapezoidal: stream << "generalized_trapezoidal"; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard input stream operator for IntegrationSchemeType inline std::istream & operator>>(std::istream & stream, IntegrationSchemeType & type) { std::string str; stream >> str; if (str == "pseudo_time") type = _ist_pseudo_time; else if (str == "forward_euler") type = _ist_forward_euler; else if (str == "trapezoidal_rule_1") type = _ist_trapezoidal_rule_1; else if (str == "backward_euler") type = _ist_backward_euler; else if (str == "central_difference") type = _ist_central_difference; else if (str == "fox_goodwin") type = _ist_fox_goodwin; else if (str == "trapezoidal_rule_2") type = _ist_trapezoidal_rule_2; else if (str == "linear_acceleration") type = _ist_linear_acceleration; else if (str == "newmark_beta") type = _ist_newmark_beta; else if (str == "generalized_trapezoidal") type = _ist_generalized_trapezoidal; else { AKANTU_ERROR("The type " << str << " is not a recognized IntegrationSchemeType"); stream.setstate(std::ios::failbit); } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for SynchronizationTag inline std::ostream & operator<<(std::ostream & stream, SynchronizationTag type) { switch (type) { case _gst_whatever: stream << "_gst_whatever"; break; case _gst_update: stream << "_gst_update"; break; case _gst_size: stream << "_gst_size"; break; case _gst_smm_mass: stream << "_gst_smm_mass"; break; case _gst_smm_for_gradu: stream << "_gst_smm_for_gradu"; break; case _gst_smm_boundary: stream << "_gst_smm_boundary"; break; case _gst_smm_uv: stream << "_gst_smm_uv"; break; case _gst_smm_res: stream << "_gst_smm_res"; break; case _gst_smm_init_mat: stream << "_gst_smm_init_mat"; break; case _gst_smm_stress: stream << "_gst_smm_stress"; break; case _gst_smmc_facets: stream << "_gst_smmc_facets"; break; case _gst_smmc_facets_conn: stream << "_gst_smmc_facets_conn"; break; case _gst_smmc_facets_stress: stream << "_gst_smmc_facets_stress"; break; case _gst_smmc_damage: stream << "_gst_smmc_damage"; break; case _gst_giu_global_conn: stream << "_gst_giu_global_conn"; break; case _gst_ce_groups: stream << "_gst_ce_groups"; break; case _gst_gm_clusters: stream << "_gst_gm_clusters"; break; case _gst_htm_capacity: stream << "_gst_htm_capacity"; break; case _gst_htm_temperature: stream << "_gst_htm_temperature"; break; case _gst_htm_gradient_temperature: stream << "_gst_htm_gradient_temperature"; break; case _gst_htm_phi: stream << "_gst_htm_phi"; break; case _gst_htm_gradient_phi: stream << "_gst_htm_gradient_phi"; break; case _gst_mnl_for_average: stream << "_gst_mnl_for_average"; break; case _gst_mnl_weight: stream << "_gst_mnl_weight"; break; case _gst_nh_criterion: stream << "_gst_nh_criterion"; break; case _gst_test: stream << "_gst_test"; break; case _gst_user_1: stream << "_gst_user_1"; break; case _gst_user_2: stream << "_gst_user_2"; break; case _gst_material_id: stream << "_gst_material_id"; break; case _gst_for_dump: stream << "_gst_for_dump"; break; case _gst_cf_nodal: stream << "_gst_cf_nodal"; break; case _gst_cf_incr: stream << "_gst_cf_incr"; break; case _gst_solver_solution: stream << "_gst_solver_solution"; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for SolveConvergenceCriteria inline std::ostream & operator<<(std::ostream & stream, const SolveConvergenceCriteria & criteria) { switch (criteria) { case _scc_residual: stream << "_scc_residual"; break; case _scc_solution: stream << "_scc_solution"; break; case _scc_residual_mass_wgh: stream << "_scc_residual_mass_wgh"; break; } return stream; } inline std::istream & operator>>(std::istream & stream, SolveConvergenceCriteria & criteria) { std::string str; stream >> str; if (str == "residual") criteria = _scc_residual; else if (str == "solution") criteria = _scc_solution; else if (str == "residual_mass_wgh") criteria = _scc_residual_mass_wgh; else { stream.setstate(std::ios::failbit); } return stream; } /* -------------------------------------------------------------------------- */ inline std::string to_lower(const std::string & str) { std::string lstr = str; std::transform(lstr.begin(), lstr.end(), lstr.begin(), (int (*)(int))tolower); return lstr; } /* -------------------------------------------------------------------------- */ inline std::string trim(const std::string & to_trim) { std::string trimed = to_trim; // left trim trimed.erase(trimed.begin(), std::find_if(trimed.begin(), trimed.end(), std::not1(std::ptr_fun<int, int>(isspace)))); // right trim trimed.erase(std::find_if(trimed.rbegin(), trimed.rend(), std::not1(std::ptr_fun<int, int>(isspace))) .base(), trimed.end()); return trimed; } } // akantu #include <cmath> namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> std::string printMemorySize(UInt size) { Real real_size = size * sizeof(T); UInt mult = 0; if (real_size != 0) mult = (std::log(real_size) / std::log(2)) / 10; std::stringstream sstr; real_size /= Real(1 << (10 * mult)); sstr << std::setprecision(2) << std::fixed << real_size; std::string size_prefix; switch (mult) { case 0: sstr << ""; break; case 1: sstr << "Ki"; break; case 2: sstr << "Mi"; break; case 3: sstr << "Gi"; break; // I started on this type of machines // (32bit computers) (Nicolas) case 4: sstr << "Ti"; break; case 5: sstr << "Pi"; break; case 6: sstr << "Ei"; break; // theoritical limit of RAM of the current // computers in 2014 (64bit computers) (Nicolas) case 7: sstr << "Zi"; break; case 8: sstr << "Yi"; break; default: AKANTU_ERROR( "The programmer in 2014 didn't thought so far (even wikipedia does not " "go further)." << " You have at least 1024 times more than a yobibit of RAM!!!" << " Just add the prefix corresponding in this switch case."); } sstr << "Byte"; return sstr.str(); } } // akantu #endif /* __AKANTU_AKA_COMMON_INLINE_IMPL_CC__ */ diff --git a/src/common/aka_compatibilty_with_cpp_standard.hh b/src/common/aka_compatibilty_with_cpp_standard.hh index ebc6b3795..35fefe790 100644 --- a/src/common/aka_compatibilty_with_cpp_standard.hh +++ b/src/common/aka_compatibilty_with_cpp_standard.hh @@ -1,147 +1,150 @@ /** * @file aka_compatibilty_with_cpp_standard.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Wed Oct 25 2017 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 10 2018 * - * @brief The content of this file is taken from the possible implementations on + * @brief The content of this file is taken from the possible implementations + * on * http://en.cppreference.com * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_static_if.hh" /* -------------------------------------------------------------------------- */ #include <tuple> #include <type_traits> #include <utility> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH__ #define __AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH__ namespace aka { // Part taken from C++14 #if __cplusplus < 201402L template <bool B, class T = void> using enable_if_t = typename enable_if<B, T>::type; #else template <bool B, class T = void> using enable_if_t = std::enable_if_t<B, T>; #endif // Part taken from C++17 #if __cplusplus < 201703L // bool_constant template <bool B> using bool_constant = std::integral_constant<bool, B>; namespace { template <bool B> constexpr bool bool_constant_v = bool_constant<B>::value; } /* -------------------------------------------------------------------------- */ // conjunction template <class...> struct conjunction : std::true_type {}; template <class B1> struct conjunction<B1> : B1 {}; template <class B1, class... Bn> struct conjunction<B1, Bn...> : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {}; /* -------------------------------------------------------------------------- */ // negations template <class B> struct negation : bool_constant<!bool(B::value)> {}; /* -------------------------------------------------------------------------- */ namespace detail { template <class T> struct is_reference_wrapper : std::false_type {}; template <class U> struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {}; // template <class T> // constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value; // template <class T, class Type, class T1, class... Args> // decltype(auto) INVOKE(Type T::*f, T1 && t1, Args &&... args) { // static_assert(std::is_member_function_pointer<decltype(f)>{} and // std::is_base_of<T, std::decay_t<T1>>{}, // "Does not know what to do with this types"); // return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...); // } template <class T, class Type, class T1, class... Args> decltype(auto) INVOKE(Type T::*f, T1 && t1, Args &&... args) { static_if(std::is_member_function_pointer<decltype(f)>{}) .then_([&](auto && f) { static_if(std::is_base_of<T, std::decay_t<T1>>{}) .then_([&](auto && f) { return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...); }) .elseif(is_reference_wrapper<std::decay_t<T1>>{})([&](auto && f) { return (t1.get().*f)(std::forward<Args>(args)...); }) .else_([&](auto && f) { return ((*std::forward<T1>(t1)).* f)(std::forward<Args>(args)...); })(std::forward<decltype(f)>(f)); }) .else_([&](auto && f) { static_assert(std::is_member_object_pointer<decltype(f)>::value, "f is not a member object"); static_assert(sizeof...(args) == 0, "f takes arguments"); static_if(std::is_base_of<T, std::decay_t<T1>>{}) .then_([&](auto && f) { return std::forward<T1>(t1).*f; }) .elseif(std::is_base_of<T, std::decay_t<T1>>{})( [&](auto && f) { return t1.get().*f; }) .else_([&](auto && f) { return (*std::forward<T1>(t1)).*f; })( std::forward<decltype(f)>(f)); })(std::forward<decltype(f)>(f)); } template <class F, class... Args> decltype(auto) INVOKE(F && f, Args &&... args) { return std::forward<F>(f)(std::forward<Args>(args)...); } } // namespace detail template <class F, class... Args> decltype(auto) invoke(F && f, Args &&... args) { return detail::INVOKE(std::forward<F>(f), std::forward<Args>(args)...); } namespace detail { template <class F, class Tuple, std::size_t... Is> constexpr decltype(auto) apply_impl(F && f, Tuple && t, std::index_sequence<Is...>) { return invoke(std::forward<F>(f), std::get<Is>(std::forward<Tuple>(t))...); } } // namespace detail template <class F, class Tuple> constexpr decltype(auto) apply(F && f, Tuple && t) { return detail::apply_impl( std::forward<F>(f), std::forward<Tuple>(t), std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}); } #endif } // namespace aka #endif /* __AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH__ */ diff --git a/src/common/aka_config.hh.in b/src/common/aka_config.hh.in index ecbec6274..321a236e4 100644 --- a/src/common/aka_config.hh.in +++ b/src/common/aka_config.hh.in @@ -1,103 +1,94 @@ /** * @file aka_config.hh.in * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sun Sep 26 2010 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Thu Jan 25 2018 * * @brief Compilation time configuration of Akantu * * @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) + * Copyright (©) 2010-2018 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 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. + * 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 <http://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public License along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_CONFIG_HH__ #define __AKANTU_AKA_CONFIG_HH__ #define AKANTU_VERSION_MAJOR @AKANTU_MAJOR_VERSION@ #define AKANTU_VERSION_MINOR @AKANTU_MINOR_VERSION@ #define AKANTU_VERSION_PATCH @AKANTU_PATCH_VERSION@ #define AKANTU_VERSION (AKANTU_VERSION_MAJOR * 10000 \ + AKANTU_VERSION_MINOR * 100 \ + AKANTU_VERSION_PATCH) @AKANTU_TYPES_EXTRA_INCLUDES@ namespace akantu { using Real = @AKANTU_FLOAT_TYPE@; using Int = @AKANTU_SIGNED_INTEGER_TYPE@; using UInt = @AKANTU_UNSIGNED_INTEGER_TYPE@; } // akantu #define AKANTU_INTEGER_SIZE @AKANTU_INTEGER_SIZE@ #define AKANTU_FLOAT_SIZE @AKANTU_FLOAT_SIZE@ #cmakedefine AKANTU_HAS_STRDUP #cmakedefine AKANTU_USE_BLAS #cmakedefine AKANTU_USE_LAPACK #cmakedefine AKANTU_PARALLEL #cmakedefine AKANTU_USE_MPI #cmakedefine AKANTU_USE_SCOTCH #cmakedefine AKANTU_USE_PTSCOTCH #cmakedefine AKANTU_SCOTCH_NO_EXTERN #cmakedefine AKANTU_IMPLICIT #cmakedefine AKANTU_USE_MUMPS #cmakedefine AKANTU_USE_PETSC #cmakedefine AKANTU_USE_IOHELPER #cmakedefine AKANTU_USE_QVIEW #cmakedefine AKANTU_USE_BLACKDYNAMITE #cmakedefine AKANTU_USE_PYBIND11 #cmakedefine AKANTU_USE_OBSOLETE_GETTIMEOFDAY #cmakedefine AKANTU_EXTRA_MATERIALS #cmakedefine AKANTU_STUDENTS_EXTRA_PACKAGE #cmakedefine AKANTU_DAMAGE_NON_LOCAL #cmakedefine AKANTU_SOLID_MECHANICS #cmakedefine AKANTU_STRUCTURAL_MECHANICS #cmakedefine AKANTU_HEAT_TRANSFER #cmakedefine AKANTU_PYTHON_INTERFACE #cmakedefine AKANTU_COHESIVE_ELEMENT #cmakedefine AKANTU_PARALLEL_COHESIVE_ELEMENT #cmakedefine AKANTU_IGFEM #cmakedefine AKANTU_USE_CGAL #cmakedefine AKANTU_EMBEDDED // Debug tools //#cmakedefine AKANTU_NDEBUG #cmakedefine AKANTU_DEBUG_TOOLS #cmakedefine READLINK_COMMAND @READLINK_COMMAND@ #cmakedefine ADDR2LINE_COMMAND @ADDR2LINE_COMMAND@ #define __aka_inline__ inline #endif /* __AKANTU_AKA_CONFIG_HH__ */ diff --git a/src/common/aka_csr.hh b/src/common/aka_csr.hh index 632b20219..7227cceee 100644 --- a/src/common/aka_csr.hh +++ b/src/common/aka_csr.hh @@ -1,259 +1,258 @@ /** * @file aka_csr.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Apr 20 2011 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Sun Dec 03 2017 * * @brief A compresed sparse row structure based on akantu Arrays * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_CSR_HH__ #define __AKANTU_AKA_CSR_HH__ namespace akantu { /** * This class can be used to store the structure of a sparse matrix or for * vectors with variable number of component per element * * @param nb_rows number of rows of a matrix or size of a vector. */ template <typename T> class CSR { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit CSR(UInt nb_rows = 0) : nb_rows(nb_rows), rows_offsets(nb_rows + 1, 1, "rows_offsets"), rows(0, 1, "rows") { rows_offsets.clear(); }; virtual ~CSR() = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// does nothing inline void beginInsertions(){}; /// insert a new entry val in row row inline UInt insertInRow(UInt row, const T & val) { UInt pos = rows_offsets(row)++; rows(pos) = val; return pos; } /// access an element of the matrix inline const T & operator()(UInt row, UInt col) const { AKANTU_DEBUG_ASSERT(rows_offsets(row + 1) - rows_offsets(row) > col, "This element is not present in this CSR"); return rows(rows_offsets(row) + col); } /// access an element of the matrix inline T & operator()(UInt row, UInt col) { AKANTU_DEBUG_ASSERT(rows_offsets(row + 1) - rows_offsets(row) > col, "This element is not present in this CSR"); return rows(rows_offsets(row) + col); } inline void endInsertions() { for (UInt i = nb_rows; i > 0; --i) rows_offsets(i) = rows_offsets(i - 1); rows_offsets(0) = 0; } inline void countToCSR() { for (UInt i = 1; i < nb_rows; ++i) rows_offsets(i) += rows_offsets(i - 1); for (UInt i = nb_rows; i >= 1; --i) rows_offsets(i) = rows_offsets(i - 1); rows_offsets(0) = 0; } inline void clearRows() { rows_offsets.clear(); rows.resize(0); }; inline void resizeRows(UInt nb_rows) { this->nb_rows = nb_rows; rows_offsets.resize(nb_rows + 1); rows_offsets.clear(); } inline void resizeCols() { rows.resize(rows_offsets(nb_rows)); } inline void copy(Array<UInt> & offsets, Array<T> & values) { offsets.copy(rows_offsets); values.copy(rows); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// returns the number of rows inline UInt getNbRows() const { return rows_offsets.size() - 1; }; /// returns the number of non-empty columns in a given row inline UInt getNbCols(UInt row) const { return rows_offsets(row + 1) - rows_offsets(row); }; /// returns the offset (start of columns) for a given row inline UInt & rowOffset(UInt row) { return rows_offsets(row); }; /// iterator on a row template <class R> class iterator_internal : public std::iterator<std::bidirectional_iterator_tag, R> { public: using _parent = std::iterator<std::bidirectional_iterator_tag, R>; using pointer = typename _parent::pointer; using reference = typename _parent::reference; explicit iterator_internal(pointer x = nullptr) : pos(x){}; iterator_internal(const iterator_internal & it) : pos(it.pos){}; iterator_internal & operator++() { ++pos; return *this; }; iterator_internal operator++(int) { iterator tmp(*this); operator++(); return tmp; }; iterator_internal & operator--() { --pos; return *this; }; iterator_internal operator--(int) { iterator_internal tmp(*this); operator--(); return tmp; }; bool operator==(const iterator_internal & rhs) { return pos == rhs.pos; }; bool operator!=(const iterator_internal & rhs) { return pos != rhs.pos; }; reference operator*() { return *pos; }; pointer operator->() const { return pos; }; private: pointer pos; }; using iterator = iterator_internal<T>; using const_iterator = iterator_internal<const T>; inline iterator begin(UInt row) { return iterator(rows.storage() + rows_offsets(row)); }; inline iterator end(UInt row) { return iterator(rows.storage() + rows_offsets(row + 1)); }; inline const_iterator begin(UInt row) const { return const_iterator(rows.storage() + rows_offsets(row)); }; inline const_iterator end(UInt row) const { return const_iterator(rows.storage() + rows_offsets(row + 1)); }; inline iterator rbegin(UInt row) { return iterator(rows.storage() + rows_offsets(row + 1) - 1); }; inline iterator rend(UInt row) { return iterator(rows.storage() + rows_offsets(row) - 1); }; inline const Array<UInt> & getRowsOffset() const { return rows_offsets; }; inline const Array<T> & getRows() const { return rows; }; inline Array<T> & getRows() { return rows; }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: UInt nb_rows; /// array of size nb_rows containing the offset where the values are stored in Array<UInt> rows_offsets; /// compressed row values, values of row[i] are stored between rows_offsets[i] /// and rows_offsets[i+1] Array<T> rows; }; /* -------------------------------------------------------------------------- */ /* Data CSR */ /* -------------------------------------------------------------------------- */ /** * Inherits from CSR<UInt> and can contain information such as matrix values * where the mother class would be a CSR structure for row and cols * * @return nb_rows */ template <class T> class DataCSR : public CSR<UInt> { public: DataCSR(UInt nb_rows = 0) : CSR<UInt>(nb_rows), data(0, 1){}; inline void resizeCols() { CSR<UInt>::resizeCols(); data.resize(rows_offsets(nb_rows)); } inline const Array<T> & getData() const { return data; }; private: Array<T> data; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ //#include "aka_csr_inline_impl.cc" /// standard output stream operator // inline std::ostream & operator <<(std::ostream & stream, const CSR & _this) // { // _this.printself(stream); // return stream; // } } // akantu #endif /* __AKANTU_AKA_CSR_HH__ */ diff --git a/src/common/aka_element_classes_info.hh.in b/src/common/aka_element_classes_info.hh.in index 1fbdeadf1..a1b6651e1 100644 --- a/src/common/aka_element_classes_info.hh.in +++ b/src/common/aka_element_classes_info.hh.in @@ -1,217 +1,209 @@ /** * @file aka_element_classes_info.hh.in * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sun Jul 19 2015 - * @date last modification: Fri Oct 16 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Declaration of the enums for the element classes * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 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. + * 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 <http://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public License along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <boost/preprocessor.hpp> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_ELEMENT_CLASSES_INFO_HH__ #define __AKANTU_AKA_ELEMENT_CLASSES_INFO_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Element Types */ /* -------------------------------------------------------------------------- */ /// @enum ElementType type of elements enum ElementType { _not_defined, @AKANTU_ELEMENT_TYPES_ENUM@ _max_element_type }; @AKANTU_ELEMENT_TYPES_BOOST_SEQ@ @AKANTU_ALL_ELEMENT_BOOST_SEQ@ /* -------------------------------------------------------------------------- */ /* Element Kinds */ /* -------------------------------------------------------------------------- */ @AKANTU_ELEMENT_KINDS_BOOST_SEQ@ @AKANTU_ELEMENT_KIND_BOOST_SEQ@ #ifndef SWIG enum ElementKind { BOOST_PP_SEQ_ENUM(AKANTU_ELEMENT_KIND), _ek_not_defined }; /* -------------------------------------------------------------------------- */ struct ElementKind_def { using type = ElementKind; static const type _begin_ = BOOST_PP_SEQ_HEAD(AKANTU_ELEMENT_KIND); static const type _end_ = _ek_not_defined; }; using element_kind_t = safe_enum<ElementKind_def> ; #else enum ElementKind; #endif /* -------------------------------------------------------------------------- */ /// @enum GeometricalType type of element potentially contained in a Mesh enum GeometricalType { @AKANTU_GEOMETRICAL_TYPES_ENUM@ _gt_not_defined }; /* -------------------------------------------------------------------------- */ /* Interpolation Types */ /* -------------------------------------------------------------------------- */ @AKANTU_INTERPOLATION_TYPES_BOOST_SEQ@ #ifndef SWIG /// @enum InterpolationType type of elements enum InterpolationType { BOOST_PP_SEQ_ENUM(AKANTU_INTERPOLATION_TYPES), _itp_not_defined }; #else enum InterpolationType; #endif /* -------------------------------------------------------------------------- */ /* Some sub types less probable to change */ /* -------------------------------------------------------------------------- */ /// @enum GeometricalShapeType types of shapes to define the contains /// function in the element classes enum GeometricalShapeType { @AKANTU_GEOMETRICAL_SHAPES_ENUM@ _gst_not_defined }; /* -------------------------------------------------------------------------- */ /// @enum GaussIntegrationType classes of types using common /// description of the gauss point position and weights enum GaussIntegrationType { @AKANTU_GAUSS_INTEGRATION_TYPES_ENUM@ _git_not_defined }; /* -------------------------------------------------------------------------- */ /// @enum InterpolationKind the family of interpolation types enum InterpolationKind { @AKANTU_INTERPOLATION_KIND_ENUM@ _itk_not_defined }; /* -------------------------------------------------------------------------- */ // BOOST PART: TOUCH ONLY IF YOU KNOW WHAT YOU ARE DOING #define AKANTU_BOOST_CASE_MACRO(r, macro, _type) \ case _type: { \ macro(_type); \ break; \ } #define AKANTU_BOOST_LIST_SWITCH(macro1, list1, var) \ do { \ switch (var) { \ BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, macro1, list1) \ default: { \ AKANTU_ERROR("Type (" << var << ") not handled by this function"); \ } \ } \ } while (0) #define AKANTU_BOOST_LIST_SWITCH_NO_DEFAULT(macro1, list1, var) \ do { \ switch (var) { \ BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, macro1, list1) \ case _not_defined: \ break; \ case _max_element_type: \ break; \ } \ } while (0) #define AKANTU_BOOST_ELEMENT_SWITCH(macro1, list1) \ AKANTU_BOOST_LIST_SWITCH(macro1, list1, type) #define AKANTU_BOOST_ELEMENT_SWITCH_NO_DEFAULT(macro1, list1) \ AKANTU_BOOST_LIST_SWITCH_NO_DEFAULT(macro1, list1, type) #define AKANTU_BOOST_ALL_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, AKANTU_ALL_ELEMENT_TYPE) #define AKANTU_BOOST_ALL_ELEMENT_SWITCH_NO_DEFAULT(macro) \ AKANTU_BOOST_ELEMENT_SWITCH_NO_DEFAULT(macro, AKANTU_ALL_ELEMENT_TYPE) #define AKANTU_BOOST_LIST_MACRO(r, macro, type) macro(type) #define AKANTU_BOOST_APPLY_ON_LIST(macro, list) \ BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_LIST_MACRO, macro, list) #define AKANTU_BOOST_ALL_ELEMENT_LIST(macro) \ AKANTU_BOOST_APPLY_ON_LIST(macro, AKANTU_ALL_ELEMENT_TYPE) #define AKANTU_GET_ELEMENT_LIST(kind) AKANTU##kind##_ELEMENT_TYPE #define AKANTU_BOOST_KIND_ELEMENT_SWITCH(macro, kind) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, AKANTU_GET_ELEMENT_LIST(kind)) // BOOST_PP_SEQ_TO_LIST does not exists in Boost < 1.49 #define AKANTU_GENERATE_KIND_LIST(seq) \ BOOST_PP_TUPLE_TO_LIST(BOOST_PP_SEQ_SIZE(seq), BOOST_PP_SEQ_TO_TUPLE(seq)) #define AKANTU_ELEMENT_KIND_BOOST_LIST \ AKANTU_GENERATE_KIND_LIST(AKANTU_ELEMENT_KIND) #define AKANTU_BOOST_ALL_KIND_LIST(macro, list) \ BOOST_PP_LIST_FOR_EACH(AKANTU_BOOST_LIST_MACRO, macro, list) #define AKANTU_BOOST_ALL_KIND(macro) \ AKANTU_BOOST_ALL_KIND_LIST(macro, AKANTU_ELEMENT_KIND_BOOST_LIST) #define AKANTU_BOOST_ALL_KIND_SWITCH(macro) \ AKANTU_BOOST_LIST_SWITCH(macro, AKANTU_ELEMENT_KIND, kind) @AKANTU_ELEMENT_KINDS_BOOST_MACROS@ // /// define kept for compatibility reasons (they are most probably not needed // /// anymore) \todo check if they can be removed // #define AKANTU_REGULAR_ELEMENT_TYPE AKANTU_ek_regular_ELEMENT_TYPE // #define AKANTU_COHESIVE_ELEMENT_TYPE AKANTU_ek_cohesive_ELEMENT_TYPE // #define AKANTU_STRUCTURAL_ELEMENT_TYPE AKANTU_ek_structural_ELEMENT_TYPE // #define AKANTU_IGFEM_ELEMENT_TYPE AKANTU_ek_igfem_ELEMENT_TYPE /* -------------------------------------------------------------------------- */ /* Lists of interests for FEEngineTemplate functions */ /* -------------------------------------------------------------------------- */ @AKANTU_FE_ENGINE_LISTS@ } // akantu #endif /* __AKANTU_AKA_ELEMENT_CLASSES_INFO_HH__ */ #include "aka_element_classes_info_inline_impl.cc" diff --git a/src/common/aka_element_classes_info_inline_impl.cc b/src/common/aka_element_classes_info_inline_impl.cc index 6bac2c4ee..871c7d2b6 100644 --- a/src/common/aka_element_classes_info_inline_impl.cc +++ b/src/common/aka_element_classes_info_inline_impl.cc @@ -1,113 +1,114 @@ /** * @file aka_element_classes_info_inline_impl.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jun 18 2015 - * @date last modification: Sun Jul 19 2015 + * @date last modification: Wed Jan 10 2018 * * @brief Implementation of the streaming fonction for the element classes * enums * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include <unordered_map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_ELEMENT_CLASSES_INFO_INLINE_IMPL_CC__ #define __AKANTU_AKA_ELEMENT_CLASSES_INFO_INLINE_IMPL_CC__ AKANTU_ENUM_HASH(ElementType) #define AKANTU_PP_ELEMTYPE_TO_STR(s, data, elem) \ ({akantu::elem, BOOST_PP_STRINGIZE(elem)}) #define AKANTU_PP_STR_TO_ELEMTYPE(s, data, elem) \ ({BOOST_PP_STRINGIZE(elem), akantu::elem}) namespace aka { inline std::string to_string(const akantu::ElementType & type) { static std::unordered_map<akantu::ElementType, std::string> convert{ BOOST_PP_SEQ_FOR_EACH_I( AKANTU_PP_ENUM, BOOST_PP_SEQ_SIZE(AKANTU_ALL_ELEMENT_TYPE), BOOST_PP_SEQ_TRANSFORM(AKANTU_PP_ELEMTYPE_TO_STR, _, AKANTU_ALL_ELEMENT_TYPE)), {akantu::_not_defined, "_not_defined"}, {akantu::_max_element_type, "_max_element_type"}}; return convert.at(type); } } namespace akantu { #define STRINGIFY(type) stream << BOOST_PP_STRINGIZE(type) /* -------------------------------------------------------------------------- */ //! standard output stream operator for ElementType inline std::ostream & operator<<(std::ostream & stream, const ElementType & type) { stream << aka::to_string(type); return stream; } /* -------------------------------------------------------------------------- */ //! standard input stream operator for ElementType inline std::istream & operator>>(std::istream & stream, ElementType & type) { std::string str; stream >> str; static std::unordered_map<std::string, ElementType> convert{ BOOST_PP_SEQ_FOR_EACH_I( AKANTU_PP_ENUM, BOOST_PP_SEQ_SIZE(AKANTU_ALL_ELEMENT_TYPE), BOOST_PP_SEQ_TRANSFORM(AKANTU_PP_STR_TO_ELEMTYPE, _, AKANTU_ALL_ELEMENT_TYPE))}; type = convert.at(str); return stream; } /* -------------------------------------------------------------------------- */ //! standard output stream operator for ElementType inline std::ostream & operator<<(std::ostream & stream, ElementKind kind) { AKANTU_BOOST_ALL_KIND_SWITCH(STRINGIFY); return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for InterpolationType inline std::ostream & operator<<(std::ostream & stream, InterpolationType type) { switch (type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, STRINGIFY, AKANTU_INTERPOLATION_TYPES) case _itp_not_defined: stream << "_itp_not_defined"; break; } return stream; } #undef STRINGIFY } // akantu #endif /* __AKANTU_AKA_ELEMENT_CLASSES_INFO_INLINE_IMPL_CC__ */ diff --git a/src/common/aka_error.cc b/src/common/aka_error.cc index bbe935cb2..1afca6656 100644 --- a/src/common/aka_error.cc +++ b/src/common/aka_error.cc @@ -1,360 +1,359 @@ /** * @file aka_error.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Sep 06 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Sun Dec 03 2017 * * @brief handling of errors * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_error.hh" #include "aka_common.hh" #include "aka_config.hh" /* -------------------------------------------------------------------------- */ #include <csignal> #include <iostream> #if (defined(READLINK_COMMAND) || defined(ADDR2LINE_COMMAND)) && \ (not defined(_WIN32)) #include <execinfo.h> #include <sys/wait.h> #endif #include <cmath> #include <cstring> #include <cxxabi.h> #include <fstream> #include <iomanip> #include <map> #include <sys/types.h> #include <unistd.h> #if defined(AKANTU_CORE_CXX11) #include <chrono> #elif defined(AKANTU_USE_OBSOLETE_GETTIMEOFDAY) #include <sys/time.h> #else #include <time.h> #endif #ifdef AKANTU_USE_MPI #include <mpi.h> #endif /* -------------------------------------------------------------------------- */ namespace akantu { namespace debug { static void printBacktraceAndExit(int) { std::terminate(); } /* ------------------------------------------------------------------------ */ void initSignalHandler() { std::signal(SIGSEGV, &printBacktraceAndExit); } /* ------------------------------------------------------------------------ */ std::string demangle(const char * symbol) { int status; std::string result; char * demangled_name; if ((demangled_name = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) != nullptr) { result = demangled_name; free(demangled_name); } else { result = symbol; } return result; } /* ------------------------------------------------------------------------ */ #if (defined(READLINK_COMMAND) || defined(ADDR2LINK_COMMAND)) && \ (not defined(_WIN32)) std::string exec(const std::string & cmd) { FILE * pipe = popen(cmd.c_str(), "r"); if (!pipe) return ""; char buffer[1024]; std::string result = ""; while (!feof(pipe)) { if (fgets(buffer, 128, pipe) != nullptr) result += buffer; } result = result.substr(0, result.size() - 1); pclose(pipe); return result; } #endif /* ------------------------------------------------------------------------ */ void printBacktrace(__attribute__((unused)) int sig) { AKANTU_DEBUG_INFO("Caught signal " << sig << "!"); #if not defined(_WIN32) #if defined(READLINK_COMMAND) && defined(ADDR2LINE_COMMAND) std::string me = ""; char buf[1024]; /* The manpage says it won't null terminate. Let's zero the buffer. */ memset(buf, 0, sizeof(buf)); /* Note we use sizeof(buf)-1 since we may need an extra char for NUL. */ if (readlink("/proc/self/exe", buf, sizeof(buf) - 1)) me = std::string(buf); std::ifstream inmaps; inmaps.open("/proc/self/maps"); std::map<std::string, size_t> addr_map; std::string line; while (inmaps.good()) { std::getline(inmaps, line); std::stringstream sstr(line); size_t first = line.find('-'); std::stringstream sstra(line.substr(0, first)); size_t addr; sstra >> std::hex >> addr; std::string lib; sstr >> lib; sstr >> lib; sstr >> lib; sstr >> lib; sstr >> lib; sstr >> lib; if (lib != "" && addr_map.find(lib) == addr_map.end()) { addr_map[lib] = addr; } } if (me != "") addr_map[me] = 0; #endif /// \todo for windows this part could be coded using CaptureStackBackTrace /// and SymFromAddr const size_t max_depth = 100; size_t stack_depth; void * stack_addrs[max_depth]; char ** stack_strings; size_t i; stack_depth = backtrace(stack_addrs, max_depth); stack_strings = backtrace_symbols(stack_addrs, stack_depth); std::cerr << "BACKTRACE : " << stack_depth << " stack frames." << std::endl; auto w = size_t(std::floor(log(double(stack_depth)) / std::log(10.)) + 1); /// -1 to remove the call to the printBacktrace function for (i = 1; i < stack_depth; i++) { std::cerr << std::dec << " [" << std::setw(w) << i << "] "; std::string bt_line(stack_strings[i]); size_t first, second; if ((first = bt_line.find('(')) != std::string::npos && (second = bt_line.find('+')) != std::string::npos) { std::string location = bt_line.substr(0, first); #if defined(READLINK_COMMAND) std::string location_cmd = std::string(BOOST_PP_STRINGIZE(READLINK_COMMAND)) + std::string(" -f ") + location; location = exec(location_cmd); #endif std::string call = demangle(bt_line.substr(first + 1, second - first - 1).c_str()); size_t f = bt_line.find('['); size_t s = bt_line.find(']'); std::string address = bt_line.substr(f + 1, s - f - 1); std::stringstream sstra(address); size_t addr; sstra >> std::hex >> addr; std::cerr << location << " [" << call << "]"; #if defined(READLINK_COMMAND) && defined(ADDR2LINE_COMMAND) auto it = addr_map.find(location); if (it != addr_map.end()) { std::stringstream syscom; syscom << BOOST_PP_STRINGIZE(ADDR2LINE_COMMAND) << " 0x" << std::hex << (addr - it->second) << " -i -e " << location; std::string line = exec(syscom.str()); std::cerr << " (" << line << ")" << std::endl; } else { #endif std::cerr << " (0x" << std::hex << addr << ")" << std::endl; #if defined(READLINK_COMMAND) && defined(ADDR2LINE_COMMAND) } #endif } else { std::cerr << bt_line << std::endl; } } free(stack_strings); std::cerr << "END BACKTRACE" << std::endl; #endif } /* ------------------------------------------------------------------------ */ namespace { void terminate_handler() { auto eptr = std::current_exception(); auto t = abi::__cxa_current_exception_type(); auto name = t ? demangle(t->name()) : std::string("unknown"); try { if (eptr) std::rethrow_exception(eptr); else std::cerr << "!! Execution terminated for unknown reasons !!" << std::endl; } catch (std::exception & e) { std::cerr << "!! Uncaught exception of type " << name << " !!\nwhat(): \"" << e.what() << "\"" << std::endl; } catch (...) { std::cerr << "!! Something strange of type \"" << name << "\" was thrown.... !!" << std::endl; } if (debugger.printBacktrace()) printBacktrace(15); } } // namespace /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ Debugger::Debugger() { cout = &std::cerr; level = dblWarning; parallel_context = ""; file_open = false; print_backtrace = false; initSignalHandler(); std::set_terminate(terminate_handler); } /* ------------------------------------------------------------------------ */ Debugger::~Debugger() { if (file_open) { dynamic_cast<std::ofstream *>(cout)->close(); delete cout; } } /* ------------------------------------------------------------------------ */ void Debugger::exit(int status) { if (status != 0) std::terminate(); std::exit(0); } /*------------------------------------------------------------------------- */ void Debugger::throwException(const std::string & info, const std::string & file, unsigned int line, __attribute__((unused)) bool silent, __attribute__((unused)) const std::string & location) const noexcept(false) { #if !defined(AKANTU_NDEBUG) if (!silent) { printMessage("###", dblWarning, info + location); } #endif debug::Exception ex(info, file, line); throw ex; } /* ------------------------------------------------------------------------ */ void Debugger::printMessage(const std::string & prefix, const DebugLevel & level, const std::string & info) const { if (this->level >= level) { #if defined(AKANTU_CORE_CXX11) double timestamp = std::chrono::duration_cast<std::chrono::duration<double, std::micro>>( std::chrono::system_clock::now().time_since_epoch()) .count(); #elif defined(AKANTU_USE_OBSOLETE_GETTIMEOFDAY) struct timeval time; gettimeofday(&time, NULL); double timestamp = time.tv_sec * 1e6 + time.tv_usec; /*in us*/ #else struct timespec time; clock_gettime(CLOCK_REALTIME_COARSE, &time); double timestamp = time.tv_sec * 1e6 + time.tv_nsec * 1e-3; /*in us*/ #endif *(cout) << parallel_context << "{" << (size_t)timestamp << "} " << prefix << " " << info << std::endl; } } /* ------------------------------------------------------------------------ */ void Debugger::setDebugLevel(const DebugLevel & level) { this->level = level; } /* ------------------------------------------------------------------------ */ const DebugLevel & Debugger::getDebugLevel() const { return this->level; } /* ------------------------------------------------------------------------ */ void Debugger::setLogFile(const std::string & filename) { if (file_open) { dynamic_cast<std::ofstream *>(cout)->close(); delete cout; } auto * fileout = new std::ofstream(filename.c_str()); file_open = true; cout = fileout; } std::ostream & Debugger::getOutputStream() { return *cout; } /* ------------------------------------------------------------------------ */ void Debugger::setParallelContext(int rank, int size) { std::stringstream sstr; UInt pad = std::ceil(std::log10(size)); sstr << "<" << getpid() << ">[R" << std::setfill(' ') << std::right << std::setw(pad) << rank << "|S" << size << "] "; parallel_context = sstr.str(); } void setDebugLevel(const DebugLevel & level) { debugger.setDebugLevel(level); } const DebugLevel & getDebugLevel() { return debugger.getDebugLevel(); } /* -------------------------------------------------------------------------- */ void exit(int status) { debugger.exit(status); } } // namespace debug } // namespace akantu diff --git a/src/common/aka_error.hh b/src/common/aka_error.hh index d06b8bb97..cf737bbc8 100644 --- a/src/common/aka_error.hh +++ b/src/common/aka_error.hh @@ -1,339 +1,339 @@ /** * @file aka_error.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 - * @date last modification: Mon Jul 13 2015 + * @date last modification: Tue Feb 20 2018 * * @brief error management and internal exceptions * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include <sstream> #include <typeinfo> #include <utility> /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ERROR_HH__ #define __AKANTU_ERROR_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ enum DebugLevel { dbl0 = 0, dblError = 0, dblAssert = 0, dbl1 = 1, dblException = 1, dblCritical = 1, dbl2 = 2, dblMajor = 2, dbl3 = 3, dblCall = 3, dblSecondary = 3, dblHead = 3, dbl4 = 4, dblWarning = 4, dbl5 = 5, dblInfo = 5, dbl6 = 6, dblIn = 6, dblOut = 6, dbl7 = 7, dbl8 = 8, dblTrace = 8, dbl9 = 9, dblAccessory = 9, dbl10 = 10, dblDebug = 42, dbl100 = 100, dblDump = 100, dblTest = 1337 }; /* -------------------------------------------------------------------------- */ #define AKANTU_LOCATION \ "(" << __func__ << "(): " << __FILE__ << ":" << __LINE__ << ")" /* -------------------------------------------------------------------------- */ namespace debug { void setDebugLevel(const DebugLevel & level); const DebugLevel & getDebugLevel(); void initSignalHandler(); std::string demangle(const char * symbol); #ifndef SWIG std::string exec(const std::string & cmd); #endif void printBacktrace(int sig); void exit(int status) __attribute__((noreturn)); /* ------------------------------------------------------------------------ */ /// exception class that can be thrown by akantu class Exception : public std::exception { /* ---------------------------------------------------------------------- */ /* Constructors/Destructors */ /* ---------------------------------------------------------------------- */ protected: explicit Exception(std::string info = "") : _info(std::move(info)), _file("") {} public: //! full constructor Exception(std::string info, std::string file, unsigned int line) : _info(std::move(info)), _file(std::move(file)), _line(line) {} //! destructor ~Exception() noexcept override = default; /* ---------------------------------------------------------------------- */ /* Methods */ /* ---------------------------------------------------------------------- */ public: const char * what() const noexcept override { return _info.c_str(); } virtual const std::string info() const noexcept { std::stringstream stream; stream << debug::demangle(typeid(*this).name()) << " : " << _info << " [" << _file << ":" << _line << "]"; return stream.str(); } public: void setInfo(const std::string & info) { _info = info; } void setFile(const std::string & file) { _file = file; } void setLine(unsigned int line) { _line = line; } /* ---------------------------------------------------------------------- */ /* Class Members */ /* ---------------------------------------------------------------------- */ protected: /// exception description and additionals std::string _info; private: /// file it is thrown from std::string _file; /// ligne it is thrown from unsigned int _line{0}; }; class CriticalError : public Exception {}; class AssertException : public Exception {}; class NotImplementedException : public Exception {}; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Exception & _this) { stream << _this.what(); return stream; } /* -------------------------------------------------------------------------- */ class Debugger { public: Debugger(); virtual ~Debugger(); Debugger(const Debugger &) = default; Debugger & operator=(const Debugger &) = default; void exit(int status) __attribute__((noreturn)); void throwException(const std::string & info, const std::string & file, unsigned int line, bool, const std::string &) const noexcept(false) __attribute__((noreturn)); /*----------------------------------------------------------------------- */ template <class Except> void throwCustomException(const Except & ex, const std::string & info, const std::string & file, unsigned int line) const noexcept(false) __attribute__((noreturn)); /*----------------------------------------------------------------------- */ template <class Except> void throwCustomException(const Except & ex, const std::string & file, unsigned int line) const noexcept(false) __attribute__((noreturn)); void printMessage(const std::string & prefix, const DebugLevel & level, const std::string & info) const; void setOutStream(std::ostream & out) { cout = &out; } std::ostream & getOutStream() { return *cout; } public: void setParallelContext(int rank, int size); void setDebugLevel(const DebugLevel & level); const DebugLevel & getDebugLevel() const; void setLogFile(const std::string & filename); std::ostream & getOutputStream(); inline bool testLevel(const DebugLevel & level) const { return (this->level >= (level)); } void printBacktrace(bool on_off) { this->print_backtrace = on_off; } bool printBacktrace() { return this->print_backtrace; } private: std::string parallel_context; std::ostream * cout; bool file_open; DebugLevel level; bool print_backtrace; }; extern Debugger debugger; } // namespace debug /* -------------------------------------------------------------------------- */ #define AKANTU_STRINGSTREAM_IN(_str, _sstr) \ ; \ do { \ std::stringstream _dbg_s_info; \ _dbg_s_info << _sstr; \ _str = _dbg_s_info.str(); \ } while (false) /* -------------------------------------------------------------------------- */ #define AKANTU_EXCEPTION(info) AKANTU_EXCEPTION_(info, false) #define AKANTU_SILENT_EXCEPTION(info) AKANTU_EXCEPTION_(info, true) #define AKANTU_EXCEPTION_(info, silent) \ do { \ std::stringstream _dbg_str; \ _dbg_str << info; \ std::stringstream _dbg_loc; \ _dbg_loc << AKANTU_LOCATION; \ ::akantu::debug::debugger.throwException( \ _dbg_str.str(), __FILE__, __LINE__, silent, _dbg_loc.str()); \ } while (false) #define AKANTU_CUSTOM_EXCEPTION_INFO(ex, info) \ do { \ std::stringstream _dbg_str; \ _dbg_str << info; \ ::akantu::debug::debugger.throwCustomException(ex, _dbg_str.str(), \ __FILE__, __LINE__); \ } while (false) #define AKANTU_CUSTOM_EXCEPTION(ex) \ do { \ ::akantu::debug::debugger.throwCustomException(ex, __FILE__, __LINE__); \ } while (false) /* -------------------------------------------------------------------------- */ #ifdef AKANTU_NDEBUG #define AKANTU_DEBUG_TEST(level) (false) #define AKANTU_DEBUG_LEVEL_IS_TEST() \ (::akantu::debug::debugger.testLevel(dblTest)) #define AKANTU_DEBUG(level, info) #define AKANTU_DEBUG_(pref, level, info) #define AKANTU_DEBUG_IN() #define AKANTU_DEBUG_OUT() #define AKANTU_DEBUG_INFO(info) #define AKANTU_DEBUG_WARNING(info) #define AKANTU_DEBUG_TRACE(info) #define AKANTU_DEBUG_ASSERT(test, info) #define AKANTU_ERROR(info) \ AKANTU_CUSTOM_EXCEPTION_INFO(::akantu::debug::CriticalError(), info) /* -------------------------------------------------------------------------- */ #else #define AKANTU_DEBUG(level, info) AKANTU_DEBUG_(" ", level, info) #define AKANTU_DEBUG_(pref, level, info) \ do { \ std::string _dbg_str; \ AKANTU_STRINGSTREAM_IN(_dbg_str, info << " " << AKANTU_LOCATION); \ ::akantu::debug::debugger.printMessage(pref, level, _dbg_str); \ } while (false) #define AKANTU_DEBUG_TEST(level) (::akantu::debug::debugger.testLevel(level)) #define AKANTU_DEBUG_LEVEL_IS_TEST() \ (::akantu::debug::debugger.testLevel(dblTest)) #define AKANTU_DEBUG_IN() \ AKANTU_DEBUG_("==>", ::akantu::dblIn, __func__ << "()") #define AKANTU_DEBUG_OUT() \ AKANTU_DEBUG_("<==", ::akantu::dblOut, __func__ << "()") #define AKANTU_DEBUG_INFO(info) AKANTU_DEBUG_("---", ::akantu::dblInfo, info) #define AKANTU_DEBUG_WARNING(info) \ AKANTU_DEBUG_("/!\\", ::akantu::dblWarning, info) #define AKANTU_DEBUG_TRACE(info) AKANTU_DEBUG_(">>>", ::akantu::dblTrace, info) #define AKANTU_DEBUG_ASSERT(test, info) \ do { \ if (not(test)) \ AKANTU_CUSTOM_EXCEPTION_INFO(::akantu::debug::AssertException(), \ "assert [" << #test << "] " << info); \ } while (false) #define AKANTU_ERROR(info) \ do { \ AKANTU_DEBUG_("!!! ", ::akantu::dblError, info); \ AKANTU_CUSTOM_EXCEPTION_INFO(::akantu::debug::CriticalError(), info); \ } while (false) #endif // AKANTU_NDEBUG #define AKANTU_TO_IMPLEMENT() \ AKANTU_CUSTOM_EXCEPTION_INFO(::akantu::debug::NotImplementedException(), \ __func__ << " : not implemented yet !") /* -------------------------------------------------------------------------- */ namespace debug { /* ------------------------------------------------------------------------ */ template <class Except> void Debugger::throwCustomException(const Except & ex, const std::string & info, const std::string & file, unsigned int line) const noexcept(false) { auto & nc_ex = const_cast<Except &>(ex); nc_ex.setInfo(info); nc_ex.setFile(file); nc_ex.setLine(line); throw ex; } /* ------------------------------------------------------------------------ */ template <class Except> void Debugger::throwCustomException(const Except & ex, const std::string & file, unsigned int line) const noexcept(false) { auto & nc_ex = const_cast<Except &>(ex); nc_ex.setFile(file); nc_ex.setLine(line); throw ex; } } // namespace debug } // namespace akantu #endif /* __AKANTU_ERROR_HH__ */ diff --git a/src/common/aka_event_handler_manager.hh b/src/common/aka_event_handler_manager.hh index 5fd229933..043493feb 100644 --- a/src/common/aka_event_handler_manager.hh +++ b/src/common/aka_event_handler_manager.hh @@ -1,126 +1,125 @@ /** * @file aka_event_handler_manager.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Wed Dec 16 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Base of Event Handler classes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_EVENT_HANDLER_MANAGER_HH__ #define __AKANTU_AKA_EVENT_HANDLER_MANAGER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <list> /* -------------------------------------------------------------------------- */ namespace akantu { template <class EventHandler> class EventHandlerManager { private: using priority_value = std::pair<EventHandlerPriority, EventHandler *>; using priority_list = std::list<priority_value>; struct KeyComp { bool operator()(const priority_value & a, const priority_value & b) const { return (a.first < b.first); } bool operator()(const priority_value & a, UInt b) const { return (a.first < b); } }; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: virtual ~EventHandlerManager() { event_handlers.clear(); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// register a new EventHandler to the Manager. The register object /// will then be informed about the events the manager observes. void registerEventHandler(EventHandler & event_handler, EventHandlerPriority priority = _ehp_highest) { auto it = this->searchEventHandler(event_handler); if (it != this->event_handlers.end()) { AKANTU_EXCEPTION("This event handler was already registered (priority: " << priority << ")"); } auto pos = std::lower_bound(this->event_handlers.begin(), this->event_handlers.end(), priority, KeyComp()); this->event_handlers.insert(pos, std::make_pair(priority, &event_handler)); } /// unregister a EventHandler object. This object will not be /// notified anymore about the events this manager observes. void unregisterEventHandler(EventHandler & event_handler) { auto it = this->searchEventHandler(event_handler); if (it == this->event_handlers.end()) { AKANTU_EXCEPTION("This event handler is not registered"); } this->event_handlers.erase(it); } /// Notify all the registered EventHandlers about the event that just occured. template <class Event> void sendEvent(const Event & event) { for (auto & pair : this->event_handlers) pair.second->sendEvent(event); } private: typename priority_list::iterator searchEventHandler(EventHandler & handler) { auto it = this->event_handlers.begin(); auto end = this->event_handlers.end(); for (; it != end && it->second != &handler; ++it) ; return it; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// list of the event handlers priority_list event_handlers; }; } // namespace akantu #endif /* __AKANTU_AKA_EVENT_HANDLER_MANAGER_HH__ */ diff --git a/src/common/aka_extern.cc b/src/common/aka_extern.cc index 78ae76cfa..f6fb3c004 100644 --- a/src/common/aka_extern.cc +++ b/src/common/aka_extern.cc @@ -1,109 +1,108 @@ /** * @file aka_extern.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 - * @date last modification: Thu Nov 19 2015 + * @date last modification: Tue Feb 20 2018 * * @brief initialisation of all global variables * to insure the order of creation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_math.hh" #include "aka_named_argument.hh" #include "aka_random_generator.hh" #include "communication_tag.hh" #include "cppargparse.hh" #include "parser.hh" #include "solid_mechanics_model.hh" #if defined(AKANTU_COHESIVE_ELEMENT) #include "solid_mechanics_model_cohesive.hh" #endif /* -------------------------------------------------------------------------- */ #include <iostream> #include <limits> /* -------------------------------------------------------------------------- */ #if defined(AKANTU_DEBUG_TOOLS) #include "aka_debug_tools.hh" #endif namespace akantu { /* -------------------------------------------------------------------------- */ /* error.hpp variables */ /* -------------------------------------------------------------------------- */ namespace debug { /** \todo write function to get this * values from the environment or a config file */ /// standard output for debug messages std::ostream * _akantu_debug_cout = &std::cerr; /// standard output for normal messages std::ostream & _akantu_cout = std::cout; /// parallel context used in debug messages std::string _parallel_context = ""; Debugger debugger; #if defined(AKANTU_DEBUG_TOOLS) DebugElementManager element_manager; #endif } // namespace debug /* -------------------------------------------------------------------------- */ /// list of ghost iterable types ghost_type_t ghost_types(_casper); /* -------------------------------------------------------------------------- */ /// Paser for commandline arguments ::cppargparse::ArgumentParser static_argparser; /// Parser containing the information parsed by the input file given to initFull Parser static_parser; bool Parser::permissive_parser = false; /* -------------------------------------------------------------------------- */ Real Math::tolerance = 1e2 * std::numeric_limits<Real>::epsilon(); /* -------------------------------------------------------------------------- */ const UInt _all_dimensions = UInt(-1); /* -------------------------------------------------------------------------- */ const Array<UInt> empty_filter(0, 1, "empty_filter"); /* -------------------------------------------------------------------------- */ template <> long int RandomGenerator<UInt>::_seed = 5489u; template <> std::default_random_engine RandomGenerator<UInt>::generator(5489u); /* -------------------------------------------------------------------------- */ int Tag::max_tag = 0; /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/common/aka_factory.hh b/src/common/aka_factory.hh index 64bd867f6..a278ef69d 100644 --- a/src/common/aka_factory.hh +++ b/src/common/aka_factory.hh @@ -1,83 +1,85 @@ /** * @file aka_factory.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Thu Jul 06 2017 + * @date creation: Sun Jul 09 2017 + * @date last modification: Fri Dec 08 2017 * - * @brief This is a generic factory + * @brief This is a generic factory * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <functional> #include <map> #include <memory> #include <string> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_FACTORY_HH__ #define __AKANTU_AKA_FACTORY_HH__ namespace akantu { template <class Base, class T = ID, class... Args> class Factory { using allocator_t = std::function<std::unique_ptr<Base>(Args...)>; private: Factory() = default; public: Factory(const Factory &) = delete; Factory & operator=(const Factory &) = delete; static Factory & getInstance() { static Factory instance; return instance; } /* ------------------------------------------------------------------------ */ bool registerAllocator(const T & id, const allocator_t & allocator) { if (allocators.find(id) != allocators.end()) AKANTU_EXCEPTION("The id " << id << " is already registered in the " << debug::demangle(typeid(Base).name()) << " factory"); allocators[id] = allocator; return true; } template <typename... AArgs> std::unique_ptr<Base> allocate(const T & id, AArgs &&... args) const { if (allocators.find(id) == allocators.end()) AKANTU_EXCEPTION("The id " << id << " is not registered in the " << debug::demangle(typeid(Base).name()) << " factory."); return std::forward<std::unique_ptr<Base>>( allocators.at(id)(std::forward<AArgs>(args)...)); } private: std::map<T, allocator_t> allocators; }; } // namespace akantu #endif /* __AKANTU_AKA_FACTORY_HH__ */ diff --git a/src/common/aka_fwd.hh b/src/common/aka_fwd.hh index 9055e696b..0ec003f5a 100644 --- a/src/common/aka_fwd.hh +++ b/src/common/aka_fwd.hh @@ -1,72 +1,72 @@ /** * @file aka_fwd.hh * * @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Apr 13 2012 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Wed Oct 25 2017 * * @brief File containing forward declarations in akantu. * This file helps if circular #include would be needed because two classes * refer both to each other. This file usually does not need any modification. * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FWD_HH__ #define __AKANTU_FWD_HH__ namespace cppargparse { class ArgumentParser; } namespace akantu { // forward declaration template <int dim, class model_type> struct ContactData; template <typename T> class Matrix; template <typename T> class Vector; template <typename T> class Tensor3; template <typename T, bool is_scal = is_scalar<T>::value> class Array; template <typename T, typename SupportType = ElementType> class ElementTypeMapArray; template <class T> class SpatialGrid; // Model element template <class ModelPolicy> class ModelElement; extern const Array<UInt> empty_filter; class Parser; class ParserSection; extern Parser static_parser; extern cppargparse::ArgumentParser static_argparser; class Mesh; class SparseMatrix; } // namespace akantu #endif /* __AKANTU_FWD_HH__ */ diff --git a/src/common/aka_grid_dynamic.hh b/src/common/aka_grid_dynamic.hh index f43007915..d717b12c8 100644 --- a/src/common/aka_grid_dynamic.hh +++ b/src/common/aka_grid_dynamic.hh @@ -1,512 +1,512 @@ /** * @file aka_grid_dynamic.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Sat Sep 26 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Grid that is auto balanced * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_types.hh" #include <iostream> /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_GRID_DYNAMIC_HH__ #define __AKANTU_AKA_GRID_DYNAMIC_HH__ namespace akantu { class Mesh; template <typename T> class SpatialGrid { public: explicit SpatialGrid(UInt dimension) : dimension(dimension), spacing(dimension), center(dimension), lower(dimension), upper(dimension), empty_cell() {} SpatialGrid(UInt dimension, const Vector<Real> & spacing, const Vector<Real> & center) : dimension(dimension), spacing(spacing), center(center), lower(dimension), upper(dimension), empty_cell() { for (UInt i = 0; i < dimension; ++i) { lower(i) = std::numeric_limits<Real>::max(); upper(i) = -std::numeric_limits<Real>::max(); } } virtual ~SpatialGrid() = default; class neighbor_cells_iterator; class cells_iterator; class CellID { public: CellID() : ids() {} explicit CellID(UInt dimention) : ids(dimention) {} void setID(UInt dir, Int id) { ids(dir) = id; } Int getID(UInt dir) const { return ids(dir); } bool operator<(const CellID & id) const { return std::lexicographical_compare( ids.storage(), ids.storage() + ids.size(), id.ids.storage(), id.ids.storage() + id.ids.size()); } bool operator==(const CellID & id) const { return std::equal(ids.storage(), ids.storage() + ids.size(), id.ids.storage()); } bool operator!=(const CellID & id) const { return !(operator==(id)); } class neighbor_cells_iterator : private std::iterator<std::forward_iterator_tag, UInt> { public: neighbor_cells_iterator(const CellID & cell_id, bool end) : cell_id(cell_id), position(cell_id.ids.size(), end ? 1 : -1) { this->updateIt(); if (end) this->it++; } neighbor_cells_iterator & operator++() { UInt i = 0; for (; i < position.size() && position(i) == 1; ++i) ; if (i == position.size()) { ++it; return *this; } for (UInt j = 0; j < i; ++j) position(j) = -1; position(i)++; updateIt(); return *this; } neighbor_cells_iterator operator++(int) { neighbor_cells_iterator tmp(*this); operator++(); return tmp; }; bool operator==(const neighbor_cells_iterator & rhs) const { return cell_id == rhs.cell_id && it == rhs.it; }; bool operator!=(const neighbor_cells_iterator & rhs) const { return !operator==(rhs); }; CellID operator*() const { CellID cur_cell_id(cell_id); cur_cell_id.ids += position; return cur_cell_id; }; private: void updateIt() { it = 0; for (UInt i = 0; i < position.size(); ++i) it = it * 3 + (position(i) + 1); } private: /// central cell id const CellID & cell_id; // number representing the current neighbor in base 3; UInt it; // current cell shift Vector<Int> position; }; class Neighbors { public: explicit Neighbors(const CellID & cell_id) : cell_id(cell_id) {} decltype(auto) begin() { return neighbor_cells_iterator(cell_id, false); } decltype(auto) end() { return neighbor_cells_iterator(cell_id, true); } private: const CellID & cell_id; }; decltype(auto) neighbors() { return Neighbors(*this); } private: friend class cells_iterator; Vector<Int> ids; }; /* ------------------------------------------------------------------------ */ class Cell { public: using iterator = typename std::vector<T>::iterator; using const_iterator = typename std::vector<T>::const_iterator; Cell() : id(), data() {} explicit Cell(const CellID & cell_id) : id(cell_id), data() {} bool operator==(const Cell & cell) const { return id == cell.id; } bool operator!=(const Cell & cell) const { return id != cell.id; } Cell & add(const T & d) { data.push_back(d); return *this; } iterator begin() { return data.begin(); } const_iterator begin() const { return data.begin(); } iterator end() { return data.end(); } const_iterator end() const { return data.end(); } private: CellID id; std::vector<T> data; }; private: using cells_container = std::map<CellID, Cell>; public: const Cell & getCell(const CellID & cell_id) const { auto it = cells.find(cell_id); if (it != cells.end()) return it->second; return empty_cell; } decltype(auto) beginCell(const CellID & cell_id) { auto it = cells.find(cell_id); if (it != cells.end()) return it->second.begin(); return empty_cell.begin(); } decltype(auto) endCell(const CellID & cell_id) { auto it = cells.find(cell_id); if (it != cells.end()) return it->second.end(); return empty_cell.end(); } decltype(auto) beginCell(const CellID & cell_id) const { auto it = cells.find(cell_id); if (it != cells.end()) return it->second.begin(); return empty_cell.begin(); } decltype(auto) endCell(const CellID & cell_id) const { auto it = cells.find(cell_id); if (it != cells.end()) return it->second.end(); return empty_cell.end(); } /* ------------------------------------------------------------------------ */ class cells_iterator : private std::iterator<std::forward_iterator_tag, CellID> { public: explicit cells_iterator(typename std::map<CellID, Cell>::const_iterator it) : it(it) {} cells_iterator & operator++() { this->it++; return *this; } cells_iterator operator++(int) { cells_iterator tmp(*this); operator++(); return tmp; }; bool operator==(const cells_iterator & rhs) const { return it == rhs.it; }; bool operator!=(const cells_iterator & rhs) const { return !operator==(rhs); }; CellID operator*() const { CellID cur_cell_id(this->it->first); return cur_cell_id; }; private: /// map iterator typename std::map<CellID, Cell>::const_iterator it; }; public: template <class vector_type> Cell & insert(const T & d, const vector_type & position) { auto && cell_id = getCellID(position); auto && it = cells.find(cell_id); if (it == cells.end()) { Cell cell(cell_id); auto & tmp = (cells[cell_id] = cell).add(d); for (UInt i = 0; i < dimension; ++i) { Real posl = center(i) + cell_id.getID(i) * spacing(i); Real posu = posl + spacing(i); if (posl < lower(i)) lower(i) = posl; if (posu > upper(i)) upper(i) = posu; } return tmp; } else { return it->second.add(d); } } /* ------------------------------------------------------------------------ */ inline decltype(auto) begin() const { auto begin = this->cells.begin(); return cells_iterator(begin); } inline decltype(auto) end() const { auto end = this->cells.end(); return cells_iterator(end); } template <class vector_type> CellID getCellID(const vector_type & position) const { CellID cell_id(dimension); for (UInt i = 0; i < dimension; ++i) { cell_id.setID(i, getCellID(position(i), i)); } return cell_id; } void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; std::streamsize prec = stream.precision(); std::ios_base::fmtflags ff = stream.flags(); stream.setf(std::ios_base::showbase); stream.precision(5); stream << space << "SpatialGrid<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; stream << space << " + dimension : " << this->dimension << std::endl; stream << space << " + lower bounds : {"; for (UInt i = 0; i < lower.size(); ++i) { if (i != 0) stream << ", "; stream << lower(i); }; stream << "}" << std::endl; stream << space << " + upper bounds : {"; for (UInt i = 0; i < upper.size(); ++i) { if (i != 0) stream << ", "; stream << upper(i); }; stream << "}" << std::endl; stream << space << " + spacing : {"; for (UInt i = 0; i < spacing.size(); ++i) { if (i != 0) stream << ", "; stream << spacing(i); }; stream << "}" << std::endl; stream << space << " + center : {"; for (UInt i = 0; i < center.size(); ++i) { if (i != 0) stream << ", "; stream << center(i); }; stream << "}" << std::endl; stream << space << " + nb_cells : " << this->cells.size() << "/"; Vector<Real> dist(this->dimension); dist = upper; dist -= lower; for (UInt i = 0; i < this->dimension; ++i) { dist(i) /= spacing(i); } UInt nb_cells = std::ceil(dist(0)); for (UInt i = 1; i < this->dimension; ++i) { nb_cells *= std::ceil(dist(i)); } stream << nb_cells << std::endl; stream << space << "]" << std::endl; stream.precision(prec); stream.flags(ff); } void saveAsMesh(Mesh & mesh) const; private: /* -------------------------------------------------------------------------- */ inline UInt getCellID(Real position, UInt direction) const { AKANTU_DEBUG_ASSERT(direction < center.size(), "The direction asked (" << direction << ") is out of range " << center.size()); Real dist_center = position - center(direction); Int id = std::floor(dist_center / spacing(direction)); // if(dist_center < 0) id--; return id; } friend class GridSynchronizer; public: AKANTU_GET_MACRO(LowerBounds, lower, const Vector<Real> &); AKANTU_GET_MACRO(UpperBounds, upper, const Vector<Real> &); AKANTU_GET_MACRO(Spacing, spacing, const Vector<Real> &); protected: UInt dimension; cells_container cells; Vector<Real> spacing; Vector<Real> center; Vector<Real> lower; Vector<Real> upper; Cell empty_cell; }; /// standard output stream operator template <typename T> inline std::ostream & operator<<(std::ostream & stream, const SpatialGrid<T> & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "mesh.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> void SpatialGrid<T>::saveAsMesh(Mesh & mesh) const { auto & nodes = const_cast<Array<Real> &>(mesh.getNodes()); ElementType type; switch (dimension) { case 1: type = _segment_2; break; case 2: type = _quadrangle_4; break; case 3: type = _hexahedron_8; break; } mesh.addConnectivityType(type); auto & connectivity = const_cast<Array<UInt> &>(mesh.getConnectivity(type)); auto & uint_data = mesh.getDataPointer<UInt>("tag_1", type); Vector<Real> pos(dimension); UInt global_id = 0; for (auto & cell_pair : cells) { UInt cur_node = nodes.size(); UInt cur_elem = connectivity.size(); const CellID & cell_id = cell_pair.first; for (UInt i = 0; i < dimension; ++i) pos(i) = center(i) + cell_id.getID(i) * spacing(i); nodes.push_back(pos); for (UInt i = 0; i < dimension; ++i) pos(i) += spacing(i); nodes.push_back(pos); connectivity.push_back(cur_node); switch (dimension) { case 1: connectivity(cur_elem, 1) = cur_node + 1; break; case 2: pos(0) -= spacing(0); nodes.push_back(pos); pos(0) += spacing(0); pos(1) -= spacing(1); nodes.push_back(pos); connectivity(cur_elem, 1) = cur_node + 3; connectivity(cur_elem, 2) = cur_node + 1; connectivity(cur_elem, 3) = cur_node + 2; break; case 3: pos(1) -= spacing(1); pos(2) -= spacing(2); nodes.push_back(pos); pos(1) += spacing(1); nodes.push_back(pos); pos(0) -= spacing(0); nodes.push_back(pos); pos(1) -= spacing(1); pos(2) += spacing(2); nodes.push_back(pos); pos(0) += spacing(0); nodes.push_back(pos); pos(0) -= spacing(0); pos(1) += spacing(1); nodes.push_back(pos); connectivity(cur_elem, 1) = cur_node + 2; connectivity(cur_elem, 2) = cur_node + 3; connectivity(cur_elem, 3) = cur_node + 4; connectivity(cur_elem, 4) = cur_node + 5; connectivity(cur_elem, 5) = cur_node + 6; connectivity(cur_elem, 6) = cur_node + 1; connectivity(cur_elem, 7) = cur_node + 7; break; } uint_data.push_back(global_id); ++global_id; } } } // namespace akantu #endif /* __AKANTU_AKA_GRID_DYNAMIC_HH__ */ diff --git a/src/common/aka_iterators.hh b/src/common/aka_iterators.hh index 7eed4b058..b9a33e8b1 100644 --- a/src/common/aka_iterators.hh +++ b/src/common/aka_iterators.hh @@ -1,352 +1,354 @@ /** * @file aka_iterators.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Wed Jul 19 2017 + * @date creation: Fri Aug 11 2017 + * @date last modification: Mon Jan 29 2018 * - * @brief iterator interfaces + * @brief iterator interfaces * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include <tuple> #include <utility> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_ITERATORS_HH__ #define __AKANTU_AKA_ITERATORS_HH__ namespace akantu { namespace tuple { /* ------------------------------------------------------------------------ */ namespace details { template <size_t N> struct Foreach { template <class Tuple> static inline bool not_equal(Tuple && a, Tuple && b) { if (std::get<N - 1>(std::forward<Tuple>(a)) == std::get<N - 1>(std::forward<Tuple>(b))) return false; return Foreach<N - 1>::not_equal(std::forward<Tuple>(a), std::forward<Tuple>(b)); } }; /* ---------------------------------------------------------------------- */ template <> struct Foreach<0> { template <class Tuple> static inline bool not_equal(Tuple && a, Tuple && b) { return std::get<0>(std::forward<Tuple>(a)) != std::get<0>(std::forward<Tuple>(b)); } }; template <typename... Ts> decltype(auto) make_tuple_no_decay(Ts &&... args) { return std::tuple<Ts...>(std::forward<Ts>(args)...); } template <class F, class Tuple, size_t... Is> void foreach_impl(F && func, Tuple && tuple, std::index_sequence<Is...> &&) { (void)std::initializer_list<int>{ (std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(tuple))), 0)...}; } template <class F, class Tuple, size_t... Is> decltype(auto) transform_impl(F && func, Tuple && tuple, std::index_sequence<Is...> &&) { return make_tuple_no_decay( std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(tuple)))...); } } // namespace details /* ------------------------------------------------------------------------ */ template <class Tuple> bool are_not_equal(Tuple && a, Tuple && b) { return details::Foreach<std::tuple_size<std::decay_t<Tuple>>::value>:: not_equal(std::forward<Tuple>(a), std::forward<Tuple>(b)); } template <class F, class Tuple> void foreach (F && func, Tuple && tuple) { return details::foreach_impl( std::forward<F>(func), std::forward<Tuple>(tuple), std::make_index_sequence< std::tuple_size<std::decay_t<Tuple>>::value>{}); } template <class F, class Tuple> decltype(auto) transform(F && func, Tuple && tuple) { return details::transform_impl( std::forward<F>(func), std::forward<Tuple>(tuple), std::make_index_sequence< std::tuple_size<std::decay_t<Tuple>>::value>{}); } } // namespace tuple /* -------------------------------------------------------------------------- */ namespace iterators { namespace { template <typename It, typename category> struct is_at_least_category : std::is_same<std::common_type_t< typename std::iterator_traits<It>::iterator_category, category>, category> {}; } template <class... Iterators> class ZipIterator { public: using value_type = std::tuple<typename std::iterator_traits<Iterators>::value_type...>; using difference_type = std::common_type_t< typename std::iterator_traits<Iterators>::difference_type...>; using pointer = std::tuple<typename std::iterator_traits<Iterators>::pointer...>; using reference = std::tuple<typename std::iterator_traits<Iterators>::reference...>; using iterator_category = std::input_iterator_tag; // std::common_type_t<typename // std::iterator_traits<Iterators>::iterator_category...>; private: using tuple_t = std::tuple<Iterators...>; public: explicit ZipIterator(tuple_t iterators) : iterators(std::move(iterators)) {} // input iterator ++it ZipIterator & operator++() { tuple::foreach ([](auto && it) { ++it; }, iterators); return *this; } // input iterator it++ ZipIterator operator++(int) { auto cpy = *this; tuple::foreach ([](auto && it) { ++it; }, iterators); return cpy; } // input iterator it != other_it bool operator!=(const ZipIterator & other) const { return tuple::are_not_equal(iterators, other.iterators); } // input iterator dereference *it decltype(auto) operator*() { return tuple::transform([](auto && it) -> decltype(auto) { return *it; }, iterators); } bool operator==(const ZipIterator & other) const { return not tuple::are_not_equal(iterators, other.iterators); } private: tuple_t iterators; }; } // namespace iterators /* -------------------------------------------------------------------------- */ template <class... Iterators> decltype(auto) zip_iterator(std::tuple<Iterators...> && iterators_tuple) { auto zip = iterators::ZipIterator<Iterators...>( std::forward<decltype(iterators_tuple)>(iterators_tuple)); return zip; } /* -------------------------------------------------------------------------- */ namespace containers { template <class... Containers> class ZipContainer { using containers_t = std::tuple<Containers...>; public: explicit ZipContainer(Containers &&... containers) : containers(std::forward<Containers>(containers)...) {} decltype(auto) begin() const { return zip_iterator( tuple::transform([](auto && c) { return c.begin(); }, std::forward<containers_t>(containers))); } decltype(auto) end() const { return zip_iterator( tuple::transform([](auto && c) { return c.end(); }, std::forward<containers_t>(containers))); } decltype(auto) begin() { return zip_iterator( tuple::transform([](auto && c) { return c.begin(); }, std::forward<containers_t>(containers))); } decltype(auto) end() { return zip_iterator( tuple::transform([](auto && c) { return c.end(); }, std::forward<containers_t>(containers))); } private: containers_t containers; }; template <class Iterator> class Range { public: explicit Range(Iterator && it1, Iterator && it2) : iterators(std::forward<Iterator>(it1), std::forward<Iterator>(it2)) {} decltype(auto) begin() const { return std::get<0>(iterators); } decltype(auto) begin() { return std::get<0>(iterators); } decltype(auto) end() const { return std::get<1>(iterators); } decltype(auto) end() { return std::get<1>(iterators); } private: std::tuple<Iterator, Iterator> iterators; }; } // namespace containers /* -------------------------------------------------------------------------- */ template <class... Containers> decltype(auto) zip(Containers &&... conts) { return containers::ZipContainer<Containers...>( std::forward<Containers>(conts)...); } template <class Iterator> decltype(auto) range(Iterator && it1, Iterator && it2) { return containers::Range<Iterator>(std::forward<Iterator>(it1), std::forward<Iterator>(it2)); } /* -------------------------------------------------------------------------- */ /* Arange */ /* -------------------------------------------------------------------------- */ namespace iterators { template <class T> class ArangeIterator { public: using value_type = T; using pointer = T *; using reference = T &; using difference_type = size_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*() const { return value; } constexpr bool operator==(const ArangeIterator & other) const { return (value == other.value) and (step == other.step); } constexpr bool operator!=(const ArangeIterator & other) const { return not operator==(other); } private: T value{0}; const T step{1}; }; } // namespace iterators namespace containers { template <class T> class ArangeContainer { public: using iterator = iterators::ArangeIterator<T>; 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 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 <class T, typename = std::enable_if_t<std::is_integral<std::decay_t<T>>::value>> inline decltype(auto) arange(const T & stop) { return containers::ArangeContainer<T>(stop); } template <class T1, class T2, typename = std::enable_if_t< std::is_integral<std::common_type_t<T1, T2>>::value>> inline constexpr decltype(auto) arange(const T1 & start, const T2 & stop) { return containers::ArangeContainer<std::common_type_t<T1, T2>>(start, stop); } template <class T1, class T2, class T3, typename = std::enable_if_t< std::is_integral<std::common_type_t<T1, T2, T3>>::value>> inline constexpr decltype(auto) arange(const T1 & start, const T2 & stop, const T3 & step) { return containers::ArangeContainer<std::common_type_t<T1, T2, T3>>( start, stop, step); } /* -------------------------------------------------------------------------- */ template <class Container> inline constexpr decltype(auto) enumerate(Container && container, size_t start_ = 0) { auto stop = std::forward<Container>(container).size(); decltype(stop) start = start_; return zip(arange(start, stop), std::forward<Container>(container)); } } // namespace akantu namespace std { template <typename... Its> struct iterator_traits<::akantu::iterators::ZipIterator<Its...>> { using iterator_category = forward_iterator_tag; using value_type = typename ::akantu::iterators::ZipIterator<Its...>::value_type; using difference_type = typename ::akantu::iterators::ZipIterator<Its...>::difference_type; using pointer = typename ::akantu::iterators::ZipIterator<Its...>::pointer; using reference = typename ::akantu::iterators::ZipIterator<Its...>::reference; }; } #endif /* __AKANTU_AKA_ITERATORS_HH__ */ diff --git a/src/common/aka_math.cc b/src/common/aka_math.cc index 09ad498d8..09bd4270d 100644 --- a/src/common/aka_math.cc +++ b/src/common/aka_math.cc @@ -1,251 +1,250 @@ /** * @file aka_math.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Peter Spijker <peter.spijker@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Aug 04 2010 - * @date last modification: Fri May 15 2015 + * @date last modification: Sun Aug 13 2017 * * @brief Implementation of the math toolbox * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_math.hh" #include "aka_array.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void Math::matrix_vector(UInt m, UInt n, const Array<Real> & A, const Array<Real> & x, Array<Real> & y, Real alpha) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(A.size() == x.size(), "The vector A(" << A.getID() << ") and the vector x(" << x.getID() << ") must have the same size"); AKANTU_DEBUG_ASSERT(A.getNbComponent() == m * n, "The vector A(" << A.getID() << ") has the good number of component."); AKANTU_DEBUG_ASSERT( x.getNbComponent() == n, "The vector x(" << x.getID() << ") do not the good number of component."); AKANTU_DEBUG_ASSERT( y.getNbComponent() == n, "The vector y(" << y.getID() << ") do not the good number of component."); UInt nb_element = A.size(); UInt offset_A = A.getNbComponent(); UInt offset_x = x.getNbComponent(); y.resize(nb_element); Real * A_val = A.storage(); Real * x_val = x.storage(); Real * y_val = y.storage(); for (UInt el = 0; el < nb_element; ++el) { matrix_vector(m, n, A_val, x_val, y_val, alpha); A_val += offset_A; x_val += offset_x; y_val += offset_x; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Math::matrix_matrix(UInt m, UInt n, UInt k, const Array<Real> & A, const Array<Real> & B, Array<Real> & C, Real alpha) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(A.size() == B.size(), "The vector A(" << A.getID() << ") and the vector B(" << B.getID() << ") must have the same size"); AKANTU_DEBUG_ASSERT(A.getNbComponent() == m * k, "The vector A(" << A.getID() << ") has the good number of component."); AKANTU_DEBUG_ASSERT( B.getNbComponent() == k * n, "The vector B(" << B.getID() << ") do not the good number of component."); AKANTU_DEBUG_ASSERT( C.getNbComponent() == m * n, "The vector C(" << C.getID() << ") do not the good number of component."); UInt nb_element = A.size(); UInt offset_A = A.getNbComponent(); UInt offset_B = B.getNbComponent(); UInt offset_C = C.getNbComponent(); C.resize(nb_element); Real * A_val = A.storage(); Real * B_val = B.storage(); Real * C_val = C.storage(); for (UInt el = 0; el < nb_element; ++el) { matrix_matrix(m, n, k, A_val, B_val, C_val, alpha); A_val += offset_A; B_val += offset_B; C_val += offset_C; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Math::matrix_matrixt(UInt m, UInt n, UInt k, const Array<Real> & A, const Array<Real> & B, Array<Real> & C, Real alpha) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(A.size() == B.size(), "The vector A(" << A.getID() << ") and the vector B(" << B.getID() << ") must have the same size"); AKANTU_DEBUG_ASSERT(A.getNbComponent() == m * k, "The vector A(" << A.getID() << ") has the good number of component."); AKANTU_DEBUG_ASSERT( B.getNbComponent() == k * n, "The vector B(" << B.getID() << ") do not the good number of component."); AKANTU_DEBUG_ASSERT( C.getNbComponent() == m * n, "The vector C(" << C.getID() << ") do not the good number of component."); UInt nb_element = A.size(); UInt offset_A = A.getNbComponent(); UInt offset_B = B.getNbComponent(); UInt offset_C = C.getNbComponent(); C.resize(nb_element); Real * A_val = A.storage(); Real * B_val = B.storage(); Real * C_val = C.storage(); for (UInt el = 0; el < nb_element; ++el) { matrix_matrixt(m, n, k, A_val, B_val, C_val, alpha); A_val += offset_A; B_val += offset_B; C_val += offset_C; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Math::compute_tangents(const Array<Real> & normals, Array<Real> & tangents) { AKANTU_DEBUG_IN(); UInt spatial_dimension = normals.getNbComponent(); UInt tangent_components = spatial_dimension * (spatial_dimension - 1); AKANTU_DEBUG_ASSERT( tangent_components == tangents.getNbComponent(), "Cannot compute the tangents, the storage array for tangents" << " does not have the good amount of components."); UInt nb_normals = normals.size(); tangents.resize(nb_normals); Real * normal_it = normals.storage(); Real * tangent_it = tangents.storage(); /// compute first tangent for (UInt q = 0; q < nb_normals; ++q) { /// if normal is orthogonal to xy plane, arbitrarly define tangent if (Math::are_float_equal(Math::norm2(normal_it), 0)) tangent_it[0] = 1; else Math::normal2(normal_it, tangent_it); normal_it += spatial_dimension; tangent_it += tangent_components; } /// compute second tangent (3D case) if (spatial_dimension == 3) { normal_it = normals.storage(); tangent_it = tangents.storage(); for (UInt q = 0; q < nb_normals; ++q) { Math::normal3(normal_it, tangent_it, tangent_it + spatial_dimension); normal_it += spatial_dimension; tangent_it += tangent_components; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real Math::reduce(Array<Real> & array) { UInt nb_values = array.size(); if (nb_values == 0) return 0.; UInt nb_values_to_sum = nb_values >> 1; std::sort(array.begin(), array.end()); // as long as the half is not empty while (nb_values_to_sum) { UInt remaining = (nb_values - 2 * nb_values_to_sum); if (remaining) array(nb_values - 2) += array(nb_values - 1); // sum to consecutive values and store the sum in the first half for (UInt i = 0; i < nb_values_to_sum; ++i) { array(i) = array(2 * i) + array(2 * i + 1); } nb_values = nb_values_to_sum; nb_values_to_sum >>= 1; } return array(0); } } // akantu diff --git a/src/common/aka_math.hh b/src/common/aka_math.hh index 3a38dfd1a..6973b22b1 100644 --- a/src/common/aka_math.hh +++ b/src/common/aka_math.hh @@ -1,292 +1,291 @@ /** * @file aka_math.hh * * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Peter Spijker <peter.spijker@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Aug 04 2010 - * @date last modification: Fri May 15 2015 + * @date last modification: Mon Sep 11 2017 * * @brief mathematical operations * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_MATH_H__ #define __AKANTU_AKA_MATH_H__ /* -------------------------------------------------------------------------- */ #include <utility> #include "aka_common.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T, bool is_scal> class Array; class Math { /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Matrix algebra */ /* ------------------------------------------------------------------------ */ /// @f$ y = A*x @f$ static void matrix_vector(UInt m, UInt n, const Array<Real, true> & A, const Array<Real, true> & x, Array<Real, true> & y, Real alpha = 1.); /// @f$ y = A*x @f$ static inline void matrix_vector(UInt m, UInt n, Real * A, Real * x, Real * y, Real alpha = 1.); /// @f$ y = A^t*x @f$ static inline void matrixt_vector(UInt m, UInt n, Real * A, Real * x, Real * y, Real alpha = 1.); /// @f$ C = A*B @f$ static void matrix_matrix(UInt m, UInt n, UInt k, const Array<Real, true> & A, const Array<Real, true> & B, Array<Real, true> & C, Real alpha = 1.); /// @f$ C = A*B^t @f$ static void matrix_matrixt(UInt m, UInt n, UInt k, const Array<Real, true> & A, const Array<Real, true> & B, Array<Real, true> & C, Real alpha = 1.); /// @f$ C = A*B @f$ static inline void matrix_matrix(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); /// @f$ C = A^t*B @f$ static inline void matrixt_matrix(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); /// @f$ C = A*B^t @f$ static inline void matrix_matrixt(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); /// @f$ C = A^t*B^t @f$ static inline void matrixt_matrixt(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); template <bool tr_A, bool tr_B> static inline void matMul(UInt m, UInt n, UInt k, Real alpha, Real * A, Real * B, Real beta, Real * C); template <bool tr_A> static inline void matVectMul(UInt m, UInt n, Real alpha, Real * A, Real * x, Real beta, Real * y); static inline void aXplusY(UInt n, Real alpha, Real * x, Real * y); static inline void matrix33_eigenvalues(Real * A, Real * Adiag); static inline void matrix22_eigenvalues(Real * A, Real * Adiag); template <UInt dim> static inline void eigenvalues(Real * A, Real * d); /// solve @f$ A x = \Lambda x @f$ and return d and V such as @f$ A V[i:] = /// d[i] V[i:]@f$ template <typename T> static void matrixEig(UInt n, T * A, T * d, T * V = nullptr); /// determinent of a 2x2 matrix static inline Real det2(const Real * mat); /// determinent of a 3x3 matrix static inline Real det3(const Real * mat); /// determinent of a nxn matrix template <UInt n> static inline Real det(const Real * mat); /// determinent of a nxn matrix template <typename T> static inline T det(UInt n, const T * mat); /// inverse a nxn matrix template <UInt n> static inline void inv(const Real * mat, Real * inv); /// inverse a nxn matrix template <typename T> static inline void inv(UInt n, const T * mat, T * inv); /// inverse a 3x3 matrix static inline void inv3(const Real * mat, Real * inv); /// inverse a 2x2 matrix static inline void inv2(const Real * mat, Real * inv); /// solve A x = b using a LU factorization template <typename T> static inline void solve(UInt n, const T * A, T * x, const T * b); /// return the double dot product between 2 tensors in 2d static inline Real matrixDoubleDot22(Real * A, Real * B); /// return the double dot product between 2 tensors in 3d static inline Real matrixDoubleDot33(Real * A, Real * B); /// extension of the double dot product to two 2nd order tensor in dimension n static inline Real matrixDoubleDot(UInt n, Real * A, Real * B); /* ------------------------------------------------------------------------ */ /* Array algebra */ /* ------------------------------------------------------------------------ */ /// vector cross product static inline void vectorProduct3(const Real * v1, const Real * v2, Real * res); /// normalize a vector static inline void normalize2(Real * v); /// normalize a vector static inline void normalize3(Real * v); /// return norm of a 2-vector static inline Real norm2(const Real * v); /// return norm of a 3-vector static inline Real norm3(const Real * v); /// return norm of a vector static inline Real norm(UInt n, const Real * v); /// return the dot product between 2 vectors in 2d static inline Real vectorDot2(const Real * v1, const Real * v2); /// return the dot product between 2 vectors in 3d static inline Real vectorDot3(const Real * v1, const Real * v2); /// return the dot product between 2 vectors static inline Real vectorDot(Real * v1, Real * v2, UInt n); /* ------------------------------------------------------------------------ */ /* Geometry */ /* ------------------------------------------------------------------------ */ /// compute normal a normal to a vector static inline void normal2(const Real * v1, Real * res); /// compute normal a normal to a vector static inline void normal3(const Real * v1, const Real * v2, Real * res); /// compute the tangents to an array of normal vectors static void compute_tangents(const Array<Real> & normals, Array<Real> & tangents); /// distance in 2D between x and y static inline Real distance_2d(const Real * x, const Real * y); /// distance in 3D between x and y static inline Real distance_3d(const Real * x, const Real * y); /// radius of the in-circle of a triangle static inline Real triangle_inradius(const Real * coord1, const Real * coord2, const Real * coord3); /// radius of the in-circle of a tetrahedron static inline Real tetrahedron_inradius(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4); /// volume of a tetrahedron static inline Real tetrahedron_volume(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4); /// compute the barycenter of n points static inline void barycenter(const Real * coord, UInt nb_points, UInt spatial_dimension, Real * barycenter); /// vector between x and y static inline void vector_2d(const Real * x, const Real * y, Real * vec); /// vector pointing from x to y in 3 spatial dimension static inline void vector_3d(const Real * x, const Real * y, Real * vec); /// test if two scalar are equal within a given tolerance static inline bool are_float_equal(Real x, Real y); /// test if two vectors are equal within a given tolerance static inline bool are_vector_equal(UInt n, Real * x, Real * y); #ifdef isnan #error \ "You probably included <math.h> which is incompatible with aka_math please use\ <cmath> or add a \"#undef isnan\" before akantu includes" #endif /// test if a real is a NaN static inline bool isnan(Real x); /// test if the line x and y intersects each other static inline bool intersects(Real x_min, Real x_max, Real y_min, Real y_max); /// test if a is in the range [x_min, x_max] static inline bool is_in_range(Real a, Real x_min, Real x_max); static inline Real getTolerance() { return tolerance; }; static inline void setTolerance(Real tol) { tolerance = tol; }; template <UInt p, typename T> static inline T pow(T x); /// reduce all the values of an array, the summation is done in place and the /// array is modified static Real reduce(Array<Real> & array); class NewtonRaphson { public: NewtonRaphson(Real tolerance, Real max_iteration) : tolerance(tolerance), max_iteration(max_iteration) {} template <class Functor> Real solve(const Functor & funct, Real x_0); private: Real tolerance; Real max_iteration; }; struct NewtonRaphsonFunctor { explicit NewtonRaphsonFunctor(std::string name) : name(std::move(name)) {} virtual ~NewtonRaphsonFunctor() = default; virtual Real f(Real x) const = 0; virtual Real f_prime(Real x) const = 0; std::string name; }; private: /// tolerance for functions that need one static Real tolerance; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "aka_math_tmpl.hh" } // akantu #endif /* __AKANTU_AKA_MATH_H__ */ diff --git a/src/common/aka_math_tmpl.hh b/src/common/aka_math_tmpl.hh index 2e0bdb5a7..599e21b3b 100644 --- a/src/common/aka_math_tmpl.hh +++ b/src/common/aka_math_tmpl.hh @@ -1,784 +1,783 @@ /** * @file aka_math_tmpl.hh * * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Mathilde Radiguet <mathilde.radiguet@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Peter Spijker <peter.spijker@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Aug 04 2010 - * @date last modification: Wed Oct 21 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of the inline functions of the math toolkit * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ } // akantu #include <cmath> #include <cstring> #include <typeinfo> #include "aka_blas_lapack.hh" namespace akantu { /* -------------------------------------------------------------------------- */ inline void Math::matrix_vector(UInt im, UInt in, Real * A, Real * x, Real * y, Real alpha) { #ifdef AKANTU_USE_BLAS /// y = alpha*op(A)*x + beta*y char tran_A = 'N'; int incx = 1; int incy = 1; double beta = 0.; int m = im; int n = in; aka_gemv(&tran_A, &m, &n, &alpha, A, &m, x, &incx, &beta, y, &incy); #else memset(y, 0, im * sizeof(Real)); for (UInt i = 0; i < im; ++i) { for (UInt j = 0; j < in; ++j) { y[i] += A[i + j * im] * x[j]; } y[i] *= alpha; } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrixt_vector(UInt im, UInt in, Real * A, Real * x, Real * y, Real alpha) { #ifdef AKANTU_USE_BLAS /// y = alpha*op(A)*x + beta*y char tran_A = 'T'; int incx = 1; int incy = 1; double beta = 0.; int m = im; int n = in; aka_gemv(&tran_A, &m, &n, &alpha, A, &m, x, &incx, &beta, y, &incy); #else memset(y, 0, in * sizeof(Real)); for (UInt i = 0; i < im; ++i) { for (UInt j = 0; j < in; ++j) { y[j] += A[j * im + i] * x[i]; } y[i] *= alpha; } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrix_matrix(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'N'; char trans_b = 'N'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &m, B, &k, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jb = j * ik; UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { for (UInt l = 0; l < ik; ++l) { UInt _la = l * im; C[i + _jc] += A[i + _la] * B[l + _jb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrixt_matrix(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'T'; char trans_b = 'N'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &k, B, &k, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; UInt _jb = j * ik; for (UInt i = 0; i < im; ++i) { UInt _ia = i * ik; for (UInt l = 0; l < ik; ++l) { C[i + _jc] += A[l + _ia] * B[l + _jb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrix_matrixt(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'N'; char trans_b = 'T'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &m, B, &n, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { for (UInt l = 0; l < ik; ++l) { UInt _la = l * im; UInt _lb = l * in; C[i + _jc] += A[i + _la] * B[j + _lb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrixt_matrixt(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'T'; char trans_b = 'T'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &k, B, &n, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { UInt _ia = i * ik; for (UInt l = 0; l < ik; ++l) { UInt _lb = l * in; C[i + _jc] += A[l + _ia] * B[j + _lb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::aXplusY(UInt n, Real alpha, Real * x, Real * y) { #ifdef AKANTU_USE_BLAS /// y := alpha x + y int incx = 1, incy = 1; aka_axpy(&n, &alpha, x, &incx, y, &incy); #else for (UInt i = 0; i < n; ++i) *(y++) += alpha * *(x++); #endif } /* -------------------------------------------------------------------------- */ inline Real Math::vectorDot(Real * v1, Real * v2, UInt in) { #ifdef AKANTU_USE_BLAS /// d := v1 . v2 int incx = 1, incy = 1, n = in; Real d = aka_dot(&n, v1, &incx, v2, &incy); #else Real d = 0; for (UInt i = 0; i < in; ++i) { d += v1[i] * v2[i]; } #endif return d; } /* -------------------------------------------------------------------------- */ template <bool tr_A, bool tr_B> inline void Math::matMul(UInt m, UInt n, UInt k, Real alpha, Real * A, Real * B, __attribute__((unused)) Real beta, Real * C) { if (tr_A) { if (tr_B) matrixt_matrixt(m, n, k, A, B, C, alpha); else matrixt_matrix(m, n, k, A, B, C, alpha); } else { if (tr_B) matrix_matrixt(m, n, k, A, B, C, alpha); else matrix_matrix(m, n, k, A, B, C, alpha); } } /* -------------------------------------------------------------------------- */ template <bool tr_A> inline void Math::matVectMul(UInt m, UInt n, Real alpha, Real * A, Real * x, __attribute__((unused)) Real beta, Real * y) { if (tr_A) { matrixt_vector(m, n, A, x, y, alpha); } else { matrix_vector(m, n, A, x, y, alpha); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void Math::matrixEig(UInt n, T * A, T * d, T * V) { // Matrix A is row major, so the lapack function in fortran will process // A^t. Asking for the left eigenvectors of A^t will give the transposed right // eigenvectors of A so in the C++ code the right eigenvectors. char jobvr, jobvl; if (V != nullptr) jobvr = 'V'; // compute left eigenvectors else jobvr = 'N'; // compute left eigenvectors jobvl = 'N'; // compute right eigenvectors auto * di = new T[n]; // imaginary part of the eigenvalues int info; int N = n; T wkopt; int lwork = -1; // query and allocate the optimal workspace aka_geev<T>(&jobvl, &jobvr, &N, A, &N, d, di, nullptr, &N, V, &N, &wkopt, &lwork, &info); lwork = int(wkopt); auto * work = new T[lwork]; // solve the eigenproblem aka_geev<T>(&jobvl, &jobvr, &N, A, &N, d, di, nullptr, &N, V, &N, work, &lwork, &info); AKANTU_DEBUG_ASSERT( info == 0, "Problem computing eigenvalues/vectors. DGEEV exited with the value " << info); delete[] work; delete[] di; // I hope for you that there was no complex eigenvalues !!! } /* -------------------------------------------------------------------------- */ inline void Math::matrix22_eigenvalues(Real * A, Real * Adiag) { /// d = determinant of Matrix A Real d = det2(A); /// b = trace of Matrix A Real b = A[0] + A[3]; Real c = sqrt(b * b - 4 * d); Adiag[0] = .5 * (b + c); Adiag[1] = .5 * (b - c); } /* -------------------------------------------------------------------------- */ inline void Math::matrix33_eigenvalues(Real * A, Real * Adiag) { matrixEig(3, A, Adiag); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Math::eigenvalues(Real * A, Real * d) { if (dim == 1) { d[0] = A[0]; } else if (dim == 2) { matrix22_eigenvalues(A, d); } // else if(dim == 3) { matrix33_eigenvalues(A, d); } else matrixEig(dim, A, d); } /* -------------------------------------------------------------------------- */ inline Real Math::det2(const Real * mat) { return mat[0] * mat[3] - mat[1] * mat[2]; } /* -------------------------------------------------------------------------- */ inline Real Math::det3(const Real * mat) { return mat[0] * (mat[4] * mat[8] - mat[7] * mat[5]) - mat[3] * (mat[1] * mat[8] - mat[7] * mat[2]) + mat[6] * (mat[1] * mat[5] - mat[4] * mat[2]); } /* -------------------------------------------------------------------------- */ template <UInt n> inline Real Math::det(const Real * mat) { if (n == 1) return *mat; else if (n == 2) return det2(mat); else if (n == 3) return det3(mat); else return det(n, mat); } /* -------------------------------------------------------------------------- */ template <typename T> inline T Math::det(UInt n, const T * A) { int N = n; int info; auto * ipiv = new int[N + 1]; auto * LU = new T[N * N]; std::copy(A, A + N * N, LU); // LU factorization of A aka_getrf(&N, &N, LU, &N, ipiv, &info); if (info > 0) { AKANTU_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } // det(A) = det(L) * det(U) = 1 * det(U) = product_i U_{ii} T det = 1.; for (int i = 0; i < N; ++i) det *= (2 * (ipiv[i] == i) - 1) * LU[i * n + i]; delete[] ipiv; delete[] LU; return det; } /* -------------------------------------------------------------------------- */ inline void Math::normal2(const Real * vec, Real * normal) { normal[0] = vec[1]; normal[1] = -vec[0]; Math::normalize2(normal); } /* -------------------------------------------------------------------------- */ inline void Math::normal3(const Real * vec1, const Real * vec2, Real * normal) { Math::vectorProduct3(vec1, vec2, normal); Math::normalize3(normal); } /* -------------------------------------------------------------------------- */ inline void Math::normalize2(Real * vec) { Real norm = Math::norm2(vec); vec[0] /= norm; vec[1] /= norm; } /* -------------------------------------------------------------------------- */ inline void Math::normalize3(Real * vec) { Real norm = Math::norm3(vec); vec[0] /= norm; vec[1] /= norm; vec[2] /= norm; } /* -------------------------------------------------------------------------- */ inline Real Math::norm2(const Real * vec) { return sqrt(vec[0] * vec[0] + vec[1] * vec[1]); } /* -------------------------------------------------------------------------- */ inline Real Math::norm3(const Real * vec) { return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]); } /* -------------------------------------------------------------------------- */ inline Real Math::norm(UInt n, const Real * vec) { Real norm = 0.; for (UInt i = 0; i < n; ++i) { norm += vec[i] * vec[i]; } return sqrt(norm); } /* -------------------------------------------------------------------------- */ inline void Math::inv2(const Real * mat, Real * inv) { Real det_mat = det2(mat); inv[0] = mat[3] / det_mat; inv[1] = -mat[1] / det_mat; inv[2] = -mat[2] / det_mat; inv[3] = mat[0] / det_mat; } /* -------------------------------------------------------------------------- */ inline void Math::inv3(const Real * mat, Real * inv) { Real det_mat = det3(mat); inv[0] = (mat[4] * mat[8] - mat[7] * mat[5]) / det_mat; inv[1] = (mat[2] * mat[7] - mat[8] * mat[1]) / det_mat; inv[2] = (mat[1] * mat[5] - mat[4] * mat[2]) / det_mat; inv[3] = (mat[5] * mat[6] - mat[8] * mat[3]) / det_mat; inv[4] = (mat[0] * mat[8] - mat[6] * mat[2]) / det_mat; inv[5] = (mat[2] * mat[3] - mat[5] * mat[0]) / det_mat; inv[6] = (mat[3] * mat[7] - mat[6] * mat[4]) / det_mat; inv[7] = (mat[1] * mat[6] - mat[7] * mat[0]) / det_mat; inv[8] = (mat[0] * mat[4] - mat[3] * mat[1]) / det_mat; } /* -------------------------------------------------------------------------- */ template <UInt n> inline void Math::inv(const Real * A, Real * Ainv) { if (n == 1) *Ainv = 1. / *A; else if (n == 2) inv2(A, Ainv); else if (n == 3) inv3(A, Ainv); else inv(n, A, Ainv); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Math::inv(UInt n, const T * A, T * invA) { int N = n; int info; auto * ipiv = new int[N + 1]; int lwork = N * N; auto * work = new T[lwork]; std::copy(A, A + n * n, invA); aka_getrf(&N, &N, invA, &N, ipiv, &info); if (info > 0) { AKANTU_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } aka_getri(&N, invA, &N, ipiv, work, &lwork, &info); if (info != 0) { AKANTU_ERROR("Cannot invert the matrix (info: " << info << " )"); } delete[] ipiv; delete[] work; } /* -------------------------------------------------------------------------- */ template <typename T> inline void Math::solve(UInt n, const T * A, T * x, const T * b) { int N = n; int info; auto * ipiv = new int[N]; auto * lu_A = new T[N * N]; std::copy(A, A + N * N, lu_A); aka_getrf(&N, &N, lu_A, &N, ipiv, &info); if (info > 0) { AKANTU_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } char trans = 'N'; int nrhs = 1; std::copy(b, b + N, x); aka_getrs(&trans, &N, &nrhs, lu_A, &N, ipiv, x, &N, &info); if (info != 0) { AKANTU_ERROR("Cannot solve the system (info: " << info << " )"); } delete[] ipiv; delete[] lu_A; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ inline Real Math::matrixDoubleDot22(Real * A, Real * B) { Real d; d = A[0] * B[0] + A[1] * B[1] + A[2] * B[2] + A[3] * B[3]; return d; } /* -------------------------------------------------------------------------- */ inline Real Math::matrixDoubleDot33(Real * A, Real * B) { Real d; d = A[0] * B[0] + A[1] * B[1] + A[2] * B[2] + A[3] * B[3] + A[4] * B[4] + A[5] * B[5] + A[6] * B[6] + A[7] * B[7] + A[8] * B[8]; return d; } /* -------------------------------------------------------------------------- */ inline Real Math::matrixDoubleDot(UInt n, Real * A, Real * B) { Real d = 0.; for (UInt i = 0; i < n; ++i) { for (UInt j = 0; j < n; ++j) { d += A[i * n + j] * B[i * n + j]; } } return d; } /* -------------------------------------------------------------------------- */ inline void Math::vectorProduct3(const Real * v1, const Real * v2, Real * res) { res[0] = v1[1] * v2[2] - v1[2] * v2[1]; res[1] = v1[2] * v2[0] - v1[0] * v2[2]; res[2] = v1[0] * v2[1] - v1[1] * v2[0]; } /* -------------------------------------------------------------------------- */ inline Real Math::vectorDot2(const Real * v1, const Real * v2) { return (v1[0] * v2[0] + v1[1] * v2[1]); } /* -------------------------------------------------------------------------- */ inline Real Math::vectorDot3(const Real * v1, const Real * v2) { return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]); } /* -------------------------------------------------------------------------- */ inline Real Math::distance_2d(const Real * x, const Real * y) { return sqrt((y[0] - x[0]) * (y[0] - x[0]) + (y[1] - x[1]) * (y[1] - x[1])); } /* -------------------------------------------------------------------------- */ inline Real Math::triangle_inradius(const Real * coord1, const Real * coord2, const Real * coord3) { /** * @f{eqnarray*}{ * r &=& A / s \\ * A &=& 1/4 * \sqrt{(a + b + c) * (a - b + c) * (a + b - c) (-a + b + c)} \\ * s &=& \frac{a + b + c}{2} * @f} */ Real a, b, c; a = distance_2d(coord1, coord2); b = distance_2d(coord2, coord3); c = distance_2d(coord1, coord3); Real s; s = (a + b + c) * 0.5; return sqrt((s - a) * (s - b) * (s - c) / s); } /* -------------------------------------------------------------------------- */ inline Real Math::distance_3d(const Real * x, const Real * y) { return sqrt((y[0] - x[0]) * (y[0] - x[0]) + (y[1] - x[1]) * (y[1] - x[1]) + (y[2] - x[2]) * (y[2] - x[2])); } /* -------------------------------------------------------------------------- */ inline Real Math::tetrahedron_volume(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4) { Real xx[9], vol; xx[0] = coord2[0]; xx[1] = coord2[1]; xx[2] = coord2[2]; xx[3] = coord3[0]; xx[4] = coord3[1]; xx[5] = coord3[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol = det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord3[0]; xx[4] = coord3[1]; xx[5] = coord3[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol -= det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord2[0]; xx[4] = coord2[1]; xx[5] = coord2[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol += det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord2[0]; xx[4] = coord2[1]; xx[5] = coord2[2]; xx[6] = coord3[0]; xx[7] = coord3[1]; xx[8] = coord3[2]; vol -= det3(xx); vol /= 6; return vol; } /* -------------------------------------------------------------------------- */ inline Real Math::tetrahedron_inradius(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4) { Real l12, l13, l14, l23, l24, l34; l12 = distance_3d(coord1, coord2); l13 = distance_3d(coord1, coord3); l14 = distance_3d(coord1, coord4); l23 = distance_3d(coord2, coord3); l24 = distance_3d(coord2, coord4); l34 = distance_3d(coord3, coord4); Real s1, s2, s3, s4; s1 = (l12 + l23 + l13) * 0.5; s1 = sqrt(s1 * (s1 - l12) * (s1 - l23) * (s1 - l13)); s2 = (l12 + l24 + l14) * 0.5; s2 = sqrt(s2 * (s2 - l12) * (s2 - l24) * (s2 - l14)); s3 = (l23 + l34 + l24) * 0.5; s3 = sqrt(s3 * (s3 - l23) * (s3 - l34) * (s3 - l24)); s4 = (l13 + l34 + l14) * 0.5; s4 = sqrt(s4 * (s4 - l13) * (s4 - l34) * (s4 - l14)); Real volume = Math::tetrahedron_volume(coord1, coord2, coord3, coord4); return 3 * volume / (s1 + s2 + s3 + s4); } /* -------------------------------------------------------------------------- */ inline void Math::barycenter(const Real * coord, UInt nb_points, UInt spatial_dimension, Real * barycenter) { memset(barycenter, 0, spatial_dimension * sizeof(Real)); for (UInt n = 0; n < nb_points; ++n) { UInt offset = n * spatial_dimension; for (UInt i = 0; i < spatial_dimension; ++i) { barycenter[i] += coord[offset + i] / (Real)nb_points; } } } /* -------------------------------------------------------------------------- */ inline void Math::vector_2d(const Real * x, const Real * y, Real * res) { res[0] = y[0] - x[0]; res[1] = y[1] - x[1]; } /* -------------------------------------------------------------------------- */ inline void Math::vector_3d(const Real * x, const Real * y, Real * res) { res[0] = y[0] - x[0]; res[1] = y[1] - x[1]; res[2] = y[2] - x[2]; } /* -------------------------------------------------------------------------- */ /// Combined absolute and relative tolerance test proposed in /// Real-time collision detection by C. Ericson (2004) inline bool Math::are_float_equal(const Real x, const Real y) { Real abs_max = std::max(std::abs(x), std::abs(y)); abs_max = std::max(abs_max, Real(1.)); return std::abs(x - y) <= (tolerance * abs_max); } /* -------------------------------------------------------------------------- */ inline bool Math::isnan(Real x) { #if defined(__INTEL_COMPILER) #pragma warning(push) #pragma warning(disable : 1572) #endif // defined(__INTEL_COMPILER) // x = x return false means x = quiet_NaN return !(x == x); #if defined(__INTEL_COMPILER) #pragma warning(pop) #endif // defined(__INTEL_COMPILER) } /* -------------------------------------------------------------------------- */ inline bool Math::are_vector_equal(UInt n, Real * x, Real * y) { bool test = true; for (UInt i = 0; i < n; ++i) { test &= are_float_equal(x[i], y[i]); } return test; } /* -------------------------------------------------------------------------- */ inline bool Math::intersects(Real x_min, Real x_max, Real y_min, Real y_max) { return !((x_max <= y_min) || (x_min >= y_max)); } /* -------------------------------------------------------------------------- */ inline bool Math::is_in_range(Real a, Real x_min, Real x_max) { return ((a >= x_min) && (a <= x_max)); } /* -------------------------------------------------------------------------- */ template <UInt p, typename T> inline T Math::pow(T x) { return (pow<p - 1, T>(x) * x); } template <> inline UInt Math::pow<0, UInt>(__attribute__((unused)) UInt x) { return (1); } template <> inline Real Math::pow<0, Real>(__attribute__((unused)) Real x) { return (1.); } /* -------------------------------------------------------------------------- */ template <class Functor> Real Math::NewtonRaphson::solve(const Functor & funct, Real x_0) { Real x = x_0; Real f_x = funct.f(x); UInt iter = 0; while (std::abs(f_x) > this->tolerance && iter < this->max_iteration) { x -= f_x / funct.f_prime(x); f_x = funct.f(x); iter++; } AKANTU_DEBUG_ASSERT(iter < this->max_iteration, "Newton Raphson (" << funct.name << ") solve did not converge in " << this->max_iteration << " iterations (tolerance: " << this->tolerance << ")"); return x; } diff --git a/src/common/aka_memory.cc b/src/common/aka_memory.cc index 006134ced..ed6c70903 100644 --- a/src/common/aka_memory.cc +++ b/src/common/aka_memory.cc @@ -1,64 +1,63 @@ /** * @file aka_memory.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief static memory wrapper * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <utility> #include "aka_memory.hh" #include "aka_static_memory.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Memory::Memory(ID id, MemoryID memory_id) : static_memory(StaticMemory::getStaticMemory()), id(std::move(id)), memory_id(memory_id) {} /* -------------------------------------------------------------------------- */ Memory::~Memory() { if (StaticMemory::isInstantiated()) { std::list<ID>::iterator it; for (it = handeld_vectors_id.begin(); it != handeld_vectors_id.end(); ++it) { AKANTU_DEBUG(dblAccessory, "Deleting the vector " << *it); static_memory.sfree(memory_id, *it); } static_memory.destroy(); } handeld_vectors_id.clear(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/common/aka_memory.hh b/src/common/aka_memory.hh index a5db23abb..d2e030a1e 100644 --- a/src/common/aka_memory.hh +++ b/src/common/aka_memory.hh @@ -1,115 +1,114 @@ /** * @file aka_memory.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief wrapper for the static_memory, all object which wants * to access the static_memory as to inherit from the class memory * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MEMORY_HH__ #define __AKANTU_MEMORY_HH__ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_static_memory.hh" /* -------------------------------------------------------------------------- */ #include <list> /* -------------------------------------------------------------------------- */ namespace akantu { class Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ protected: Memory(ID id, MemoryID memory_id = 0); virtual ~Memory(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// malloc template <class T> inline Array<T> & alloc(const ID & name, UInt size, UInt nb_component); /// malloc template <class T> inline Array<T> & alloc(const ID & name, UInt size, UInt nb_component, const T & init_value); /* ------------------------------------------------------------------------ */ /// free an array inline void dealloc(const ID & name); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ protected: template <typename T> inline Array<T> & getArray(const ID & name); template <typename T> inline const Array<T> & getArray(const ID & name) const; public: AKANTU_GET_MACRO(MemoryID, memory_id, const MemoryID &); AKANTU_GET_MACRO(ID, id, const ID &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// the static memory instance StaticMemory & static_memory; /// list of allocated vectors id std::list<ID> handeld_vectors_id; protected: ID id; /// the id registred in the static memory MemoryID memory_id; }; /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_INCLUDE_INLINE_IMPL) #include "aka_memory_inline_impl.cc" #endif } // akantu #endif /* __AKANTU_MEMORY_HH__ */ diff --git a/src/common/aka_memory_inline_impl.cc b/src/common/aka_memory_inline_impl.cc index eec8da71a..70cb0e538 100644 --- a/src/common/aka_memory_inline_impl.cc +++ b/src/common/aka_memory_inline_impl.cc @@ -1,66 +1,65 @@ /** * @file aka_memory_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jul 15 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief Implementation of the inline functions of the class Memory * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ template <class T> inline Array<T> & Memory::alloc(const ID & name, UInt size, UInt nb_component) { handeld_vectors_id.push_back(name); return static_memory.smalloc<T>(memory_id, name, size, nb_component); } /* -------------------------------------------------------------------------- */ template <class T> inline Array<T> & Memory::alloc(const ID & name, UInt size, UInt nb_component, const T & init_value) { handeld_vectors_id.push_back(name); return static_memory.smalloc<T>(memory_id, name, size, nb_component, init_value); } /* -------------------------------------------------------------------------- */ inline void Memory::dealloc(const ID & name) { AKANTU_DEBUG(dblAccessory, "Deleting the vector " << name); static_memory.sfree(memory_id, name); handeld_vectors_id.remove(name); } /* -------------------------------------------------------------------------- */ template <class T> inline Array<T> & Memory::getArray(const ID & name) { return static_cast<Array<T> &>( const_cast<ArrayBase &>(static_memory.getArray(memory_id, name))); } /* -------------------------------------------------------------------------- */ template <class T> inline const Array<T> & Memory::getArray(const ID & name) const { return static_cast<Array<T> &>( const_cast<ArrayBase &>(static_memory.getArray(memory_id, name))); } diff --git a/src/common/aka_named_argument.hh b/src/common/aka_named_argument.hh index 2f8f8f3d7..53a366d15 100644 --- a/src/common/aka_named_argument.hh +++ b/src/common/aka_named_argument.hh @@ -1,164 +1,194 @@ +/** + * @file aka_named_argument.hh + * + * @author Nicolas Richart <nicolas.richart@epfl.ch> + * + * @date creation: Fri Jun 16 2017 + * @date last modification: Wed Dec 06 2017 + * + * @brief tool to use named arguments in functions + * + * @section LICENSE + * + * Copyright (©) 2016-2018 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 <http://www.gnu.org/licenses/>. + * + */ + /** * @file aka_named_argument.hh * * @author Marco Arena * * @date creation Fri Jun 16 2017 * * @brief A Documented file. * * @section LICENSE * * Public Domain ? https://gist.github.com/ilpropheta/7576dce4c3249df89f85 * */ /* -------------------------------------------------------------------------- */ #include "aka_compatibilty_with_cpp_standard.hh" /* -------------------------------------------------------------------------- */ #include <tuple> #include <type_traits> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_NAMED_ARGUMENT_HH__ #define __AKANTU_AKA_NAMED_ARGUMENT_HH__ namespace akantu { namespace named_argument { struct param_t_trait {}; /* -- Pack utils (proxy version) ------------------------------------------ */ /// Proxy containing [tag, value] template <typename tag, typename type> struct param_t : param_t_trait { using _tag = tag; using _type = type; template <typename T> explicit param_t(T && value) : _value(std::forward<T>(value)) {} type _value; }; /* * Tagged proxy that allows syntax _name = value * operator=(T&&) returns a param_t instance **/ template <typename tag> struct param_proxy { using _tag = tag; template <typename T> decltype(auto) operator=(T && value) { return param_t<tag, decltype(value)>{std::forward<T>(value)}; } }; /* Same as type_at but it's supposed to be used by passing a pack of param_t (_tag is looked for instead of a plain type). This and type_at should be refactored. */ template <typename T, typename head, typename... tail> struct type_at_p { enum { _tmp = (std::is_same<T, typename std::decay_t<head>::_tag>::value) ? 0 : type_at_p<T, tail...>::_pos }; enum { _pos = _tmp == -1 ? -1 : 1 + _tmp }; }; template <typename T, typename head> struct type_at_p<T, head> { enum { _pos = (std::is_same<T, typename std::decay<head>::type::_tag>::value ? 1 : -1) }; }; template <typename... Ts> struct type_at { enum { _pos = -1 }; }; template <typename T, typename head, typename... tail> struct type_at<T, head, tail...> { enum { _tmp = type_at_p<T, head, tail...>::_pos }; enum { _pos = _tmp == 1 ? 0 : (_tmp == -1 ? -1 : _tmp - 1) }; }; /* Same as get_at but it's supposed to be used by passing a pack of param_t (_type is retrieved instead) This and get_at should be refactored. */ template <int pos, int curr> struct get_at { static_assert(pos >= 0, "Required parameter"); template <typename head, typename... tail> static decltype(auto) get(head &&, tail &&... t) { return get_at<pos, curr + 1>::get(std::forward<tail>(t)...); } }; template <int pos> struct get_at<pos, pos> { static_assert(pos >= 0, "Required parameter"); template <typename head, typename... tail> static decltype(auto) get(head && h, tail &&...) { return std::forward<decltype(h._value)>(h._value); } }; // Optional version template <int pos, int curr> struct get_optional { template <typename T, typename... pack> static decltype(auto) get(T &&, pack &&... _pack) { return get_at<pos, curr>::get(std::forward<pack>(_pack)...); } }; template <int curr> struct get_optional<-1, curr> { template <typename T, typename... pack> static decltype(auto) get(T && _default, pack &&...) { return std::forward<T>(_default); } }; } // namespace named_argument // CONVENIENCE MACROS FOR CLASS DESIGNERS ========== #define TAG_OF_ARGUMENT(_name) p_##_name #define TAG_OF_ARGUMENT_WNS(_name) TAG_OF_ARGUMENT(_name) #define REQUIRED_NAMED_ARG(_name) \ named_argument::get_at< \ named_argument::type_at<TAG_OF_ARGUMENT_WNS(_name), pack...>::_pos, \ 0>::get(std::forward<pack>(_pack)...) #define REQUIRED_NAMED_ARG(_name) \ named_argument::get_at< \ named_argument::type_at<TAG_OF_ARGUMENT_WNS(_name), pack...>::_pos, \ 0>::get(std::forward<pack>(_pack)...) #define OPTIONAL_NAMED_ARG(_name, _defaultVal) \ named_argument::get_optional< \ named_argument::type_at<TAG_OF_ARGUMENT_WNS(_name), pack...>::_pos, \ 0>::get(_defaultVal, std::forward<pack>(_pack)...) #define DECLARE_NAMED_ARGUMENT(name) \ struct TAG_OF_ARGUMENT(name) {}; \ named_argument::param_proxy<TAG_OF_ARGUMENT_WNS(name)> _##name \ __attribute__((unused)) namespace { struct use_named_args_t {}; use_named_args_t use_named_args __attribute__((unused)); } // namespace template <typename T> struct is_named_argument : public std::false_type {}; template <typename... type> struct is_named_argument<named_argument::param_t<type...>> : public std::true_type {}; template <typename... pack> using are_named_argument = aka::conjunction<is_named_argument<std::decay_t<pack>>...>; } // namespace akantu #endif /* __AKANTU_AKA_NAMED_ARGUMENT_HH__ */ diff --git a/src/common/aka_random_generator.hh b/src/common/aka_random_generator.hh index 7cda1a505..5bbb5a501 100644 --- a/src/common/aka_random_generator.hh +++ b/src/common/aka_random_generator.hh @@ -1,268 +1,268 @@ /** * @file aka_random_generator.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Wed Nov 11 2015 + * @date last modification: Wed Nov 08 2017 * * @brief generic random generator * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" /* -------------------------------------------------------------------------- */ #include <random> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_RANDOM_GENERATOR_HH__ #define __AKANTU_AKA_RANDOM_GENERATOR_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* List of available distributions */ /* -------------------------------------------------------------------------- */ // clang-format off #define AKANTU_RANDOM_DISTRIBUTION_TYPES \ ((uniform , std::uniform_real_distribution )) \ ((exponential , std::exponential_distribution )) \ ((gamma , std::gamma_distribution )) \ ((weibull , std::weibull_distribution )) \ ((extreme_value, std::extreme_value_distribution)) \ ((normal , std::normal_distribution )) \ ((lognormal , std::lognormal_distribution )) \ ((chi_squared , std::chi_squared_distribution )) \ ((cauchy , std::cauchy_distribution )) \ ((fisher_f , std::fisher_f_distribution )) \ ((student_t , std::student_t_distribution )) // clang-format on #define AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX(elem) BOOST_PP_CAT(_rdt_, elem) #define AKANTU_RANDOM_DISTRIBUTION_PREFIX(s, data, elem) \ AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX(BOOST_PP_TUPLE_ELEM(2, 0, elem)) enum RandomDistributionType { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(AKANTU_RANDOM_DISTRIBUTION_PREFIX, _, AKANTU_RANDOM_DISTRIBUTION_TYPES)), _rdt_not_defined }; /* -------------------------------------------------------------------------- */ /* Generator */ /* -------------------------------------------------------------------------- */ template <typename T> class RandomGenerator { /* ------------------------------------------------------------------------ */ public: inline T operator()() { return generator(); } /// function to print the contain of the class virtual void printself(std::ostream & stream, int) const { stream << "RandGenerator [seed=" << _seed << "]"; } /* ------------------------------------------------------------------------ */ public: static void seed(long int s) { _seed = s; generator.seed(_seed); } static long int seed() { return _seed; } static constexpr T min() { return generator.min(); } static constexpr T max() { return generator.max(); } /* ------------------------------------------------------------------------ */ private: static long int _seed; static std::default_random_engine generator; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #undef AKANTU_RANDOM_DISTRIBUTION_PREFIX #define AKANTU_RANDOM_DISTRIBUTION_TYPE_PRINT_CASE(r, data, elem) \ case AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX( \ BOOST_PP_TUPLE_ELEM(2, 0, elem)): { \ stream << BOOST_PP_STRINGIZE(AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX( \ BOOST_PP_TUPLE_ELEM(2, 0, elem))); \ break; \ } inline std::ostream & operator<<(std::ostream & stream, RandomDistributionType type) { switch (type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_RANDOM_DISTRIBUTION_TYPE_PRINT_CASE, _, AKANTU_RANDOM_DISTRIBUTION_TYPES) default: stream << UInt(type) << " not a RandomDistributionType"; break; } return stream; } #undef AKANTU_RANDOM_DISTRIBUTION_TYPE_PRINT_CASE /* -------------------------------------------------------------------------- */ /* Some Helper */ /* -------------------------------------------------------------------------- */ template <typename T, class Distribution> class RandomDistributionTypeHelper { enum { value = _rdt_not_defined }; }; /* -------------------------------------------------------------------------- */ #define AKANTU_RANDOM_DISTRIBUTION_TYPE_GET_TYPE(r, data, elem) \ template <typename T> \ struct RandomDistributionTypeHelper< \ T, BOOST_PP_TUPLE_ELEM(2, 1, elem) < T>> { \ enum { \ value = AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX( \ BOOST_PP_TUPLE_ELEM(2, 0, elem)) \ }; \ \ static void printself(std::ostream & stream) { \ stream << BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, elem)); \ } \ }; BOOST_PP_SEQ_FOR_EACH(AKANTU_RANDOM_DISTRIBUTION_TYPE_GET_TYPE, _, AKANTU_RANDOM_DISTRIBUTION_TYPES) #undef AKANTU_RANDOM_DISTRIBUTION_TYPE_GET_TYPE /* -------------------------------------------------------------------------- */ template <class T> class RandomDistribution { public: virtual ~RandomDistribution() = default; virtual T operator()(RandomGenerator<UInt> & gen) = 0; virtual std::unique_ptr<RandomDistribution<T>> make_unique() const = 0; virtual void printself(std::ostream & stream, int = 0) const = 0; }; template <class T, class Distribution> class RandomDistributionProxy : public RandomDistribution<T> { public: explicit RandomDistributionProxy(Distribution dist) : distribution(std::move(dist)) {} T operator()(RandomGenerator<UInt> & gen) override { return distribution(gen); } std::unique_ptr<RandomDistribution<T>> make_unique() const override { return std::make_unique<RandomDistributionProxy<T, Distribution>>( distribution); } void printself(std::ostream & stream, int = 0) const override { RandomDistributionTypeHelper<T, Distribution>::printself(stream); stream << " [ " << distribution << " ]"; } private: Distribution distribution; }; /* -------------------------------------------------------------------------- */ /* RandomParameter */ /* -------------------------------------------------------------------------- */ template <typename T> class RandomParameter { public: template <class Distribution> explicit RandomParameter(T base_value, Distribution dist) : base_value(base_value), type(RandomDistributionType( RandomDistributionTypeHelper<T, Distribution>::value)), distribution_proxy( std::make_unique<RandomDistributionProxy<T, Distribution>>( std::move(dist))) {} explicit RandomParameter(T base_value) : base_value(base_value), type(RandomDistributionType( RandomDistributionTypeHelper< T, std::uniform_real_distribution<T>>::value)), distribution_proxy( std::make_unique< RandomDistributionProxy<T, std::uniform_real_distribution<T>>>( std::uniform_real_distribution<T>(0., 0.))) {} RandomParameter(const RandomParameter & other) : base_value(other.base_value), type(other.type), distribution_proxy(other.distribution_proxy->make_unique()) {} RandomParameter & operator=(const RandomParameter & other) { distribution_proxy = other.distribution_proxy->make_unique(); base_value = other.base_value; type = other.type; return *this; } virtual ~RandomParameter() = default; inline void setBaseValue(const T & value) { this->base_value = value; } inline T getBaseValue() const { return this->base_value; } template <template <typename> class Generator, class iterator> void setValues(iterator it, iterator end) { RandomGenerator<UInt> gen; for (; it != end; ++it) *it = this->base_value + (*distribution_proxy)(gen); } virtual void printself(std::ostream & stream, __attribute__((unused)) int indent = 0) const { stream << base_value; stream << " + " << *distribution_proxy; } private: /// Value with no random variations T base_value; /// Random distribution type RandomDistributionType type; /// Proxy to store a std random distribution std::unique_ptr<RandomDistribution<T>> distribution_proxy; }; /* -------------------------------------------------------------------------- */ template <typename T> inline std::ostream & operator<<(std::ostream & stream, RandomDistribution<T> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ template <typename T> inline std::ostream & operator<<(std::ostream & stream, RandomParameter<T> & _this) { _this.printself(stream); return stream; } } // akantu #endif /* __AKANTU_AKA_RANDOM_GENERATOR_HH__ */ diff --git a/src/common/aka_safe_enum.hh b/src/common/aka_safe_enum.hh index b27885dd1..2fd2a57bb 100644 --- a/src/common/aka_safe_enum.hh +++ b/src/common/aka_safe_enum.hh @@ -1,86 +1,86 @@ /** * @file aka_safe_enum.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Tue Nov 07 2017 * * @brief Safe enums type (see More C++ Idioms/Type Safe Enum on Wikibooks * http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Safe_Enum) * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_SAFE_ENUM_HH__ #define __AKANTU_AKA_SAFE_ENUM_HH__ namespace akantu { /// Safe enumerated type template <typename def, typename inner = typename def::type> class safe_enum : public def { using type = typename def::type; public: explicit safe_enum(type v = def::_end_) : val(v) {} safe_enum(safe_enum && other) = default; safe_enum & operator=(safe_enum && other) = default; inner underlying() const { return val; } bool operator==(const safe_enum & s) const { return this->val == s.val; } bool operator!=(const safe_enum & s) const { return this->val != s.val; } bool operator<(const safe_enum & s) const { return this->val < s.val; } bool operator<=(const safe_enum & s) const { return this->val <= s.val; } bool operator>(const safe_enum & s) const { return this->val > s.val; } bool operator>=(const safe_enum & s) const { return this->val >= s.val; } operator inner() { return val; }; public: // Works only if enumerations are contiguous. class iterator { public: explicit iterator(type v) : it(v) {} iterator & operator++() { ++it; return *this; } safe_enum operator*() { return safe_enum(static_cast<type>(it)); } bool operator!=(iterator const & it) { return it.it != this->it; } private: int it; }; static iterator begin() { return iterator(def::_begin_); } static iterator end() { return iterator(def::_end_); } protected: inner val; }; } // akantu #endif /* __AKANTU_AKA_SAFE_ENUM_HH__ */ diff --git a/src/common/aka_static_if.hh b/src/common/aka_static_if.hh index 29a9bae34..cc77f848d 100644 --- a/src/common/aka_static_if.hh +++ b/src/common/aka_static_if.hh @@ -1,94 +1,29 @@ -// 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 <utility> - -#define FWD(...) ::std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__) - -namespace akantu { - -template <typename TPredicate> auto static_if(TPredicate) noexcept; - -namespace impl { - template <bool TPredicateResult> struct static_if_impl; - - template <typename TFunctionToCall> struct static_if_result; - - template <typename TF> auto make_static_if_result(TF && f) noexcept; - - template <> struct static_if_impl<true> { - template <typename TF> auto & else_(TF &&) noexcept { - // Ignore `else_`, as the predicate is true. - return *this; - } - - template <typename TPredicate> auto & else_if(TPredicate) noexcept { - // Ignore `else_if`, as the predicate is true. - return *this; - } - - template <typename TF> 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<false> { - template <typename TF> auto & then(TF &&) noexcept { - // Ignore `then`, as the predicate is false. - return *this; - } - - template <typename TF> 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 <typename TPredicate> auto else_if(TPredicate) noexcept { - return static_if(TPredicate{}); - } - - template <typename... Ts> auto operator()(Ts &&...) noexcept { - // If there are no `else` branches, we must ignore calls - // to a failed `static_if` matching. - } - }; - - template <typename TFunctionToCall> - struct static_if_result : TFunctionToCall { - // Perfect-forward the function in the result instance. - template <typename TFFwd> - explicit static_if_result(TFFwd && f) noexcept : TFunctionToCall(FWD(f)) {} - - // Ignore everything, we found a result. - template <typename TF> auto & then(TF &&) noexcept { return *this; } - - template <typename TPredicate> auto & else_if(TPredicate) noexcept { - return *this; - } - - template <typename TF> auto & else_(TF &&) noexcept { return *this; } - }; - - template <typename TF> auto make_static_if_result(TF && f) noexcept { - return static_if_result<TF>{FWD(f)}; - } -} // namespace impl - -template <typename TPredicate> auto static_if(TPredicate) noexcept { - return impl::static_if_impl<TPredicate{}>{}; -} - -#undef FWD -} // namespace akantu - -#endif /* __AKANTU_AKA_STATIC_IF_HH__ */ +/** + * @file aka_static_if.hh + * + * @author Nicolas Richart <nicolas.richart@epfl.ch> + * + * @date creation: Sun Aug 13 2017 + * @date last modification: Wed Oct 25 2017 + * + * @brief if constexpr equivalent in c++14 + * + * @section LICENSE + * + * Copyright (©) 2016-2018 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 <http://www.gnu.org/licenses/>. + * + */ diff --git a/src/common/aka_static_memory.cc b/src/common/aka_static_memory.cc index a3a18b7aa..b1e9d8efa 100644 --- a/src/common/aka_static_memory.cc +++ b/src/common/aka_static_memory.cc @@ -1,161 +1,160 @@ /** * @file aka_static_memory.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Wed Jan 06 2016 + * @date last modification: Wed Nov 08 2017 * * @brief Memory management * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <sstream> #include <stdexcept> /* -------------------------------------------------------------------------- */ #include "aka_static_memory.hh" /* -------------------------------------------------------------------------- */ namespace akantu { bool StaticMemory::is_instantiated = false; StaticMemory * StaticMemory::single_static_memory = nullptr; UInt StaticMemory::nb_reference = 0; /* -------------------------------------------------------------------------- */ StaticMemory & StaticMemory::getStaticMemory() { if (!single_static_memory) { single_static_memory = new StaticMemory(); is_instantiated = true; } nb_reference++; return *single_static_memory; } /* -------------------------------------------------------------------------- */ void StaticMemory::destroy() { nb_reference--; if (nb_reference == 0) { delete single_static_memory; } } /* -------------------------------------------------------------------------- */ StaticMemory::~StaticMemory() { AKANTU_DEBUG_IN(); MemoryMap::iterator memory_it; for (memory_it = memories.begin(); memory_it != memories.end(); ++memory_it) { ArrayMap::iterator vector_it; for (vector_it = (memory_it->second).begin(); vector_it != (memory_it->second).end(); ++vector_it) { delete vector_it->second; } (memory_it->second).clear(); } memories.clear(); is_instantiated = false; StaticMemory::single_static_memory = nullptr; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StaticMemory::sfree(const MemoryID & memory_id, const ID & name) { AKANTU_DEBUG_IN(); try { auto & vectors = const_cast<ArrayMap &>(getMemory(memory_id)); ArrayMap::iterator vector_it; vector_it = vectors.find(name); if (vector_it != vectors.end()) { AKANTU_DEBUG_INFO("Array " << name << " removed from the static memory number " << memory_id); delete vector_it->second; vectors.erase(vector_it); AKANTU_DEBUG_OUT(); return; } } catch (debug::Exception e) { AKANTU_EXCEPTION("The memory " << memory_id << " does not exist (perhaps already freed) [" << e.what() << "]"); AKANTU_DEBUG_OUT(); return; } AKANTU_DEBUG_INFO("The vector " << name << " does not exist (perhaps already freed)"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StaticMemory::printself(std::ostream & stream, int indent) const { std::string space = ""; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; std::streamsize prec = stream.precision(); stream.precision(2); stream << space << "StaticMemory [" << std::endl; UInt nb_memories = memories.size(); stream << space << " + nb memories : " << nb_memories << std::endl; Real tot_size = 0; MemoryMap::const_iterator memory_it; for (memory_it = memories.begin(); memory_it != memories.end(); ++memory_it) { Real mem_size = 0; stream << space << AKANTU_INDENT << "Memory [" << std::endl; UInt mem_id = memory_it->first; stream << space << AKANTU_INDENT << " + memory id : " << mem_id << std::endl; UInt nb_vectors = (memory_it->second).size(); stream << space << AKANTU_INDENT << " + nb vectors : " << nb_vectors << std::endl; stream.precision(prec); ArrayMap::const_iterator vector_it; for (vector_it = (memory_it->second).begin(); vector_it != (memory_it->second).end(); ++vector_it) { (vector_it->second)->printself(stream, indent + 2); mem_size += (vector_it->second)->getMemorySize(); } stream << space << AKANTU_INDENT << " + total size : " << printMemorySize<char>(mem_size) << std::endl; stream << space << AKANTU_INDENT << "]" << std::endl; tot_size += mem_size; } stream << space << " + total size : " << printMemorySize<char>(tot_size) << std::endl; stream << space << "]" << std::endl; stream.precision(prec); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/common/aka_static_memory.hh b/src/common/aka_static_memory.hh index 3fddb5de0..e80897c65 100644 --- a/src/common/aka_static_memory.hh +++ b/src/common/aka_static_memory.hh @@ -1,157 +1,156 @@ /** * @file aka_static_memory.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Sun Dec 03 2017 * * @brief Memory management * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * The class handling the memory, allocation/reallocation/desallocation * The objects can register their array and ask for allocation or realocation * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STATIC_MEMORY_HH__ #define __AKANTU_STATIC_MEMORY_HH__ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ namespace akantu { using ArrayMap = std::map<ID, ArrayBase *>; using MemoryMap = std::map<MemoryID, ArrayMap>; /** * @class StaticMemory * @brief Class for memory management common to all objects (this class as to * be accessed by an interface class memory) */ class StaticMemory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ private: /// Default constructor StaticMemory() = default; public: virtual ~StaticMemory(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get the global instance of the StaticMemory static StaticMemory & getStaticMemory(); static bool isInstantiated() { return is_instantiated; }; /// remove a reference on the static memory void destroy(); /// access to an Array inline const ArrayBase & getArray(const MemoryID & memory_id, const ID & name) const; /// get all vectors of a memory inline const ArrayMap & getMemory(const MemoryID & memory_id) const; /* ------------------------------------------------------------------------ */ /* Class Methods */ /* ------------------------------------------------------------------------ */ public: /** * Allocation of an array of type * * @param memory_id the id of the memory accessing to the static memory * @param name name of the array (for example connectivity) * @param size number of size (for example number of nodes) * @param nb_component number of component (for example spatial dimension) * @param type the type code of the array to be allocated * * @return pointer to an array of size nb_tupes * nb_component * sizeof(T) */ template <typename T> Array<T> & smalloc(const MemoryID & memory_id, const ID & name, UInt size, UInt nb_component); template <typename T> Array<T> & smalloc(const MemoryID & memory_id, const ID & name, UInt size, UInt nb_component, const T & init_value); /** * free the memory associated to the array name * * @param memory_id the id of the memory accessing to the static memory * @param name the name of an existing array */ void sfree(const MemoryID & memory_id, const ID & name); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// is the static memory instantiated static bool is_instantiated; /// unique instance of the StaticMemory static StaticMemory * single_static_memory; /// map of all allocated arrays, indexed by their names MemoryMap memories; /// number of references on the static memory static UInt nb_reference; }; #include "aka_static_memory_inline_impl.cc" #include "aka_static_memory_tmpl.hh" /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const StaticMemory & _this) { _this.printself(stream); return stream; } } // namespace akantu #endif /* __AKANTU_STATIC_MEMORY_HH__ */ diff --git a/src/common/aka_static_memory_inline_impl.cc b/src/common/aka_static_memory_inline_impl.cc index cc245ebaf..a0cc61fab 100644 --- a/src/common/aka_static_memory_inline_impl.cc +++ b/src/common/aka_static_memory_inline_impl.cc @@ -1,65 +1,64 @@ /** * @file aka_static_memory_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jul 15 2010 - * @date last modification: Fri May 22 2015 + * @date last modification: Wed Feb 03 2016 * * @brief Implementation of inline functions of the class StaticMemory * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline const ArrayMap & StaticMemory::getMemory(const MemoryID & memory_id) const { AKANTU_DEBUG_IN(); MemoryMap::const_iterator memory_it; memory_it = memories.find(memory_id); if (memory_it == memories.end()) { AKANTU_SILENT_EXCEPTION("StaticMemory as no memory with ID " << memory_id); } AKANTU_DEBUG_OUT(); return memory_it->second; } /* -------------------------------------------------------------------------- */ inline const ArrayBase & StaticMemory::getArray(const MemoryID & memory_id, const ID & name) const { AKANTU_DEBUG_IN(); const ArrayMap & vectors = getMemory(memory_id); ArrayMap::const_iterator vectors_it; vectors_it = vectors.find(name); if (vectors_it == vectors.end()) { AKANTU_SILENT_EXCEPTION("StaticMemory as no array named " << name << " for the Memory " << memory_id); } AKANTU_DEBUG_OUT(); return *(vectors_it->second); } /* -------------------------------------------------------------------------- */ diff --git a/src/common/aka_static_memory_tmpl.hh b/src/common/aka_static_memory_tmpl.hh index 484f7f125..b938bed9d 100644 --- a/src/common/aka_static_memory_tmpl.hh +++ b/src/common/aka_static_memory_tmpl.hh @@ -1,87 +1,86 @@ /** * @file aka_static_memory_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jul 15 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Tue Feb 20 2018 * * @brief template part of the StaticMemory * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ template <typename T> Array<T> & StaticMemory::smalloc(const MemoryID & memory_id, const ID & name, UInt size, UInt nb_component) { AKANTU_DEBUG_IN(); MemoryMap::iterator memory_it; memory_it = memories.find(memory_id); if (memory_it == memories.end()) { memories[memory_id] = ArrayMap(); memory_it = memories.find(memory_id); } if ((memory_it->second).find(name) != (memory_it->second).end()) { AKANTU_ERROR("The vector \"" << name << "\" is already registred in the memory " << memory_id); } auto * tmp_vect = new Array<T>(size, nb_component, name); (memory_it->second)[name] = tmp_vect; AKANTU_DEBUG_OUT(); return *tmp_vect; } /* -------------------------------------------------------------------------- */ template <typename T> Array<T> & StaticMemory::smalloc(const MemoryID & memory_id, const ID & name, UInt size, UInt nb_component, const T & init_value) { AKANTU_DEBUG_IN(); MemoryMap::iterator memory_it; memory_it = memories.find(memory_id); if (memory_it == memories.end()) { memories[memory_id] = ArrayMap(); memory_it = memories.find(memory_id); } if ((memory_it->second).find(name) != (memory_it->second).end()) { AKANTU_ERROR("The vector \"" << name << "\" is already registred in the memory " << memory_id); } auto * tmp_vect = new Array<T>(size, nb_component, init_value, name); (memory_it->second)[name] = tmp_vect; AKANTU_DEBUG_OUT(); return *tmp_vect; } /* -------------------------------------------------------------------------- */ diff --git a/src/common/aka_typelist.hh b/src/common/aka_typelist.hh index 1eb75cdfe..aa295594d 100644 --- a/src/common/aka_typelist.hh +++ b/src/common/aka_typelist.hh @@ -1,155 +1,155 @@ /** * @file aka_typelist.hh * * @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Jun 19 2017 * * @brief Objects that support the visitor design pattern * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TYPELIST_HH__ #define __AKANTU_TYPELIST_HH__ #include "aka_common.hh" namespace akantu { struct Empty_type {}; class Null_type {}; template <class T, class U> struct Typelist { typedef T Head; typedef U Tail; }; template <typename T1 = Null_type, typename T2 = Null_type, typename T3 = Null_type, typename T4 = Null_type, typename T5 = Null_type, typename T6 = Null_type, typename T7 = Null_type, typename T8 = Null_type, typename T9 = Null_type, typename T10 = Null_type, typename T11 = Null_type, typename T12 = Null_type, typename T13 = Null_type, typename T14 = Null_type, typename T15 = Null_type, typename T16 = Null_type, typename T17 = Null_type, typename T18 = Null_type, typename T19 = Null_type, typename T20 = Null_type> struct MakeTypelist { private: typedef typename MakeTypelist<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>::Result TailResult; public: typedef Typelist<T1, TailResult> Result; }; template <> struct MakeTypelist<> { typedef Null_type Result; }; //////////////////////////////////////////////////////////////////////////////// // class template Length // Computes the length of a typelist // Invocation (TList is a typelist): // Length<TList>::value // returns a compile-time constant containing the length of TList, not counting // the end terminator (which by convention is Null_type) //////////////////////////////////////////////////////////////////////////////// template <class TList> struct Length; template <> struct Length<Null_type> { enum { value = 0 }; }; template <class T, class U> struct Length<Typelist<T, U>> { enum { value = 1 + Length<U>::value }; }; //////////////////////////////////////////////////////////////////////////////// // class template TypeAt // Finds the type at a given index in a typelist // Invocation (TList is a typelist and index is a compile-time integral // constant): // TypeAt<TList, index>::Result // returns the type in position 'index' in TList // If you pass an out-of-bounds index, the result is a compile-time error //////////////////////////////////////////////////////////////////////////////// template <class TList, unsigned int index> struct TypeAt; template <class Head, class Tail> struct TypeAt<Typelist<Head, Tail>, 0> { typedef Head Result; }; template <class Head, class Tail, unsigned int i> struct TypeAt<Typelist<Head, Tail>, i> { typedef typename TypeAt<Tail, i - 1>::Result Result; }; //////////////////////////////////////////////////////////////////////////////// // class template Erase // Erases the first occurence, if any, of a type in a typelist // Invocation (TList is a typelist and T is a type): // Erase<TList, T>::Result // returns a typelist that is TList without the first occurence of T //////////////////////////////////////////////////////////////////////////////// template <class TList, class T> struct Erase; template <class T> // Specialization 1 struct Erase<Null_type, T> { typedef Null_type Result; }; template <class T, class Tail> // Specialization 2 struct Erase<Typelist<T, Tail>, T> { typedef Tail Result; }; template <class Head, class Tail, class T> // Specialization 3 struct Erase<Typelist<Head, Tail>, T> { typedef Typelist<Head, typename Erase<Tail, T>::Result> Result; }; template <class TList, class T> struct IndexOf; template <class T> struct IndexOf<Null_type, T> { enum { value = -1 }; }; template <class T, class Tail> struct IndexOf<Typelist<T, Tail>, T> { enum { value = 0 }; }; template <class Head, class Tail, class T> struct IndexOf<Typelist<Head, Tail>, T> { private: enum { temp = IndexOf<Tail, T>::value }; public: enum { value = (temp == -1 ? -1 : 1 + temp) }; }; } // akantu #endif /* __AKANTU_TYPELIST_HH__ */ diff --git a/src/common/aka_types.hh b/src/common/aka_types.hh index 09c422ee7..33e1d3aaf 100644 --- a/src/common/aka_types.hh +++ b/src/common/aka_types.hh @@ -1,1302 +1,1301 @@ /** * @file aka_types.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 17 2011 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Tue Feb 20 2018 * * @brief description of the "simple" types * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_error.hh" #include "aka_fwd.hh" #include "aka_math.hh" /* -------------------------------------------------------------------------- */ #include <initializer_list> #include <iomanip> #include <type_traits> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_TYPES_HH__ #define __AKANTU_AKA_TYPES_HH__ namespace akantu { enum NormType { L_1 = 1, L_2 = 2, L_inf = UInt(-1) }; /** * DimHelper is a class to generalize the setup of a dim array from 3 * values. This gives a common interface in the TensorStorage class * independently of its derived inheritance (Vector, Matrix, Tensor3) * @tparam dim */ template <UInt dim> struct DimHelper { static inline void setDims(UInt m, UInt n, UInt p, UInt dims[dim]); }; /* -------------------------------------------------------------------------- */ template <> struct DimHelper<1> { static inline void setDims(UInt m, __attribute__((unused)) UInt n, __attribute__((unused)) UInt p, UInt dims[1]) { dims[0] = m; } }; /* -------------------------------------------------------------------------- */ template <> struct DimHelper<2> { static inline void setDims(UInt m, UInt n, __attribute__((unused)) UInt p, UInt dims[2]) { dims[0] = m; dims[1] = n; } }; /* -------------------------------------------------------------------------- */ template <> struct DimHelper<3> { static inline void setDims(UInt m, UInt n, UInt p, UInt dims[3]) { dims[0] = m; dims[1] = n; dims[2] = p; } }; /* -------------------------------------------------------------------------- */ template <typename T, UInt ndim, class RetType> class TensorStorage; /* -------------------------------------------------------------------------- */ /* Proxy classes */ /* -------------------------------------------------------------------------- */ namespace tensors { template <class A, class B> struct is_copyable { enum : bool { value = false }; }; template <class A> struct is_copyable<A, A> { enum : bool { value = true }; }; template <class A> struct is_copyable<A, typename A::RetType> { enum : bool { value = true }; }; template <class A> struct is_copyable<A, typename A::RetType::proxy> { enum : bool { value = true }; }; } // namespace tensors /** * @class TensorProxy aka_types.hh * @desc The TensorProxy class is a proxy class to the TensorStorage it handles * the * wrapped case. That is to say if an accessor should give access to a Tensor * wrapped on some data, like the Array<T>::iterator they can return a * TensorProxy that will be automatically transformed as a TensorStorage wrapped * on the same data * @tparam T stored type * @tparam ndim order of the tensor * @tparam RetType real derived type */ template <typename T, UInt ndim, class _RetType> class TensorProxy { protected: using RetTypeProxy = typename _RetType::proxy; constexpr TensorProxy(T * data, UInt m, UInt n, UInt p) { DimHelper<ndim>::setDims(m, n, p, this->n); this->values = data; } #ifndef SWIG template <class Other, typename = std::enable_if_t< tensors::is_copyable<TensorProxy, Other>::value>> explicit TensorProxy(const Other & other) { this->values = other.storage(); for (UInt i = 0; i < ndim; ++i) this->n[i] = other.size(i); } #endif public: using RetType = _RetType; UInt size(UInt i) const { AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim << " dimensions, not " << (i + 1)); return n[i]; } inline UInt size() const { UInt _size = 1; for (UInt d = 0; d < ndim; ++d) _size *= this->n[d]; return _size; } T * storage() const { return values; } #ifndef SWIG template <class Other, typename = std::enable_if_t< tensors::is_copyable<TensorProxy, Other>::value>> inline TensorProxy & operator=(const Other & other) { AKANTU_DEBUG_ASSERT( other.size() == this->size(), "You are trying to copy two tensors with different sizes"); memcpy(this->values, other.storage(), this->size() * sizeof(T)); return *this; } #endif // template <class Other, typename = std::enable_if_t< // tensors::is_copyable<TensorProxy, Other>::value>> // inline TensorProxy & operator=(const Other && other) { // AKANTU_DEBUG_ASSERT( // other.size() == this->size(), // "You are trying to copy two tensors with different sizes"); // memcpy(this->values, other.storage(), this->size() * sizeof(T)); // return *this; // } template <typename O> inline RetTypeProxy & operator*=(const O & o) { RetType(*this) *= o; return static_cast<RetTypeProxy &>(*this); } template <typename O> inline RetTypeProxy & operator/=(const O & o) { RetType(*this) /= o; return static_cast<RetTypeProxy &>(*this); } protected: T * values; UInt n[ndim]; }; /* -------------------------------------------------------------------------- */ template <typename T> class VectorProxy : public TensorProxy<T, 1, Vector<T>> { using parent = TensorProxy<T, 1, Vector<T>>; using type = Vector<T>; public: constexpr VectorProxy(T * data, UInt n) : parent(data, n, 0, 0) {} template <class Other> explicit VectorProxy(Other & src) : parent(src) {} /* ---------------------------------------------------------------------- */ template <class Other> inline VectorProxy<T> & operator=(const Other & other) { parent::operator=(other); return *this; } // inline VectorProxy<T> & operator=(const VectorProxy && other) { // parent::operator=(other); // return *this; // } /* ------------------------------------------------------------------------ */ T & operator()(UInt index) { return this->values[index]; }; const T & operator()(UInt index) const { return this->values[index]; }; }; template <typename T> class MatrixProxy : public TensorProxy<T, 2, Matrix<T>> { using parent = TensorProxy<T, 2, Matrix<T>>; using type = Matrix<T>; public: MatrixProxy(T * data, UInt m, UInt n) : parent(data, m, n, 0) {} template <class Other> explicit MatrixProxy(Other & src) : parent(src) {} /* ---------------------------------------------------------------------- */ template <class Other> inline MatrixProxy<T> & operator=(const Other & other) { parent::operator=(other); return *this; } }; template <typename T> class Tensor3Proxy : public TensorProxy<T, 3, Tensor3<T>> { using parent = TensorProxy<T, 3, Tensor3<T>>; using type = Tensor3<T>; public: Tensor3Proxy(const T * data, UInt m, UInt n, UInt k) : parent(data, m, n, k) {} Tensor3Proxy(const Tensor3Proxy & src) : parent(src) {} Tensor3Proxy(const Tensor3<T> & src) : parent(src) {} /* ---------------------------------------------------------------------- */ template <class Other> inline Tensor3Proxy<T> & operator=(const Other & other) { parent::operator=(other); return *this; } }; /* -------------------------------------------------------------------------- */ /* Tensor base class */ /* -------------------------------------------------------------------------- */ template <typename T, UInt ndim, class RetType> class TensorStorage : public TensorTrait { public: using value_type = T; friend class Array<T>; protected: template <class TensorType> void copySize(const TensorType & src) { for (UInt d = 0; d < ndim; ++d) this->n[d] = src.size(d); this->_size = src.size(); } TensorStorage() : values(nullptr) { for (UInt d = 0; d < ndim; ++d) this->n[d] = 0; _size = 0; } TensorStorage(const TensorProxy<T, ndim, RetType> & proxy) { this->copySize(proxy); this->values = proxy.storage(); this->wrapped = true; } public: TensorStorage(const TensorStorage & src) = delete; TensorStorage(const TensorStorage & src, bool deep_copy) : values(nullptr) { if (deep_copy) this->deepCopy(src); else this->shallowCopy(src); } protected: TensorStorage(UInt m, UInt n, UInt p, const T & def) { static_assert(std::is_trivially_constructible<T>{}, "Cannot create a tensor on non trivial types"); DimHelper<ndim>::setDims(m, n, p, this->n); this->computeSize(); this->values = new T[this->_size]; this->set(def); this->wrapped = false; } TensorStorage(T * data, UInt m, UInt n, UInt p) { DimHelper<ndim>::setDims(m, n, p, this->n); this->computeSize(); this->values = data; this->wrapped = true; } public: /* ------------------------------------------------------------------------ */ template <class TensorType> inline void shallowCopy(const TensorType & src) { this->copySize(src); if (!this->wrapped) delete[] this->values; this->values = src.storage(); this->wrapped = true; } /* ------------------------------------------------------------------------ */ template <class TensorType> inline void deepCopy(const TensorType & src) { this->copySize(src); if (!this->wrapped) delete[] this->values; static_assert(std::is_trivially_constructible<T>{}, "Cannot create a tensor on non trivial types"); this->values = new T[this->_size]; static_assert(std::is_trivially_copyable<T>{}, "Cannot copy a tensor on non trivial types"); memcpy((void *)this->values, (void *)src.storage(), this->_size * sizeof(T)); this->wrapped = false; } virtual ~TensorStorage() { if (!this->wrapped) delete[] this->values; } /* ------------------------------------------------------------------------ */ inline TensorStorage & operator=(const TensorStorage & src) { return this->operator=(dynamic_cast<RetType &>(src)); } /* ------------------------------------------------------------------------ */ inline TensorStorage & operator=(const RetType & src) { if (this != &src) { if (this->wrapped) { static_assert(std::is_trivially_copyable<T>{}, "Cannot copy a tensor on non trivial types"); // this test is not sufficient for Tensor of order higher than 1 AKANTU_DEBUG_ASSERT(this->_size == src.size(), "Tensors of different size"); memcpy((void *)this->values, (void *)src.storage(), this->_size * sizeof(T)); } else { deepCopy(src); } } return *this; } /* ------------------------------------------------------------------------ */ template <class R> inline RetType & operator+=(const TensorStorage<T, ndim, R> & other) { T * a = this->storage(); T * b = other.storage(); AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); for (UInt i = 0; i < _size; ++i) *(a++) += *(b++); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ template <class R> inline RetType & operator-=(const TensorStorage<T, ndim, R> & other) { T * a = this->storage(); T * b = other.storage(); AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); for (UInt i = 0; i < _size; ++i) *(a++) -= *(b++); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator+=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) += x; return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator-=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) -= x; return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator*=(const T & x) { T * a = this->storage(); for (UInt i = 0; i < _size; ++i) *(a++) *= x; return *(static_cast<RetType *>(this)); } /* ---------------------------------------------------------------------- */ inline RetType & operator/=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) /= x; return *(static_cast<RetType *>(this)); } /// Y = \alpha X + Y inline RetType & aXplusY(const TensorStorage & other, const T & alpha = 1.) { AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); Math::aXplusY(this->_size, alpha, other.storage(), this->storage()); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ T * storage() const { return values; } UInt size() const { return _size; } UInt size(UInt i) const { AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim << " dimensions, not " << (i + 1)); return n[i]; }; /* ------------------------------------------------------------------------ */ inline void clear() { memset(values, 0, _size * sizeof(T)); }; inline void set(const T & t) { std::fill_n(values, _size, t); }; template <class TensorType> inline void copy(const TensorType & other) { AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be copied"); memcpy(values, other.storage(), _size * sizeof(T)); } bool isWrapped() const { return this->wrapped; } protected: inline void computeSize() { _size = 1; for (UInt d = 0; d < ndim; ++d) _size *= this->n[d]; } protected: template <typename R, NormType norm_type> struct NormHelper { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += std::pow(std::abs(*it), norm_type); return std::pow(_norm, 1. / norm_type); } }; template <typename R> struct NormHelper<R, L_1> { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += std::abs(*it); return _norm; } }; template <typename R> struct NormHelper<R, L_2> { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += *it * *it; return sqrt(_norm); } }; template <typename R> struct NormHelper<R, L_inf> { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm = std::max(std::abs(*it), _norm); return _norm; } }; public: /*----------------------------------------------------------------------- */ /// "Entrywise" norm norm<L_p> @f[ \|\boldsymbol{T}\|_p = \left( /// \sum_i^{n[0]}\sum_j^{n[1]}\sum_k^{n[2]} |T_{ijk}|^p \right)^{\frac{1}{p}} /// @f] template <NormType norm_type> inline T norm() const { return NormHelper<T, norm_type>::norm(*this); } protected: UInt n[ndim]; UInt _size; T * values; bool wrapped{false}; }; /* -------------------------------------------------------------------------- */ /* Vector */ /* -------------------------------------------------------------------------- */ template <typename T> class Vector : public TensorStorage<T, 1, Vector<T>> { using parent = TensorStorage<T, 1, Vector<T>>; public: using value_type = typename parent::value_type; using proxy = VectorProxy<T>; public: Vector() : parent() {} explicit Vector(UInt n, const T & def = T()) : parent(n, 0, 0, def) {} Vector(T * data, UInt n) : parent(data, n, 0, 0) {} Vector(const Vector & src, bool deep_copy = true) : parent(src, deep_copy) {} Vector(const TensorProxy<T, 1, Vector> & src) : parent(src) {} Vector(std::initializer_list<T> list) : parent(list.size(), 0, 0, T()) { UInt i = 0; for (auto val : list) { operator()(i++) = val; } } public: ~Vector() override = default; /* ------------------------------------------------------------------------ */ inline Vector & operator=(const Vector & src) { parent::operator=(src); return *this; } /* ------------------------------------------------------------------------ */ inline T & operator()(UInt i) { AKANTU_DEBUG_ASSERT((i < this->n[0]), "Access out of the vector! " << "Index (" << i << ") is out of the vector of size (" << this->n[0] << ")"); return *(this->values + i); } inline const T & operator()(UInt i) const { AKANTU_DEBUG_ASSERT((i < this->n[0]), "Access out of the vector! " << "Index (" << i << ") is out of the vector of size (" << this->n[0] << ")"); return *(this->values + i); } inline T & operator[](UInt i) { return this->operator()(i); } inline const T & operator[](UInt i) const { return this->operator()(i); } /* ------------------------------------------------------------------------ */ inline Vector<T> & operator*=(Real x) { return parent::operator*=(x); } inline Vector<T> & operator/=(Real x) { return parent::operator/=(x); } /* ------------------------------------------------------------------------ */ inline Vector<T> & operator*=(const Vector<T> & vect) { T * a = this->storage(); T * b = vect.storage(); for (UInt i = 0; i < this->_size; ++i) *(a++) *= *(b++); return *this; } /* ------------------------------------------------------------------------ */ inline Real dot(const Vector<T> & vect) const { return Math::vectorDot(this->values, vect.storage(), this->_size); } /* ------------------------------------------------------------------------ */ inline Real mean() const { Real mean = 0; T * a = this->storage(); for (UInt i = 0; i < this->_size; ++i) mean += *(a++); return mean / this->_size; } /* ------------------------------------------------------------------------ */ inline Vector & crossProduct(const Vector<T> & v1, const Vector<T> & v2) { AKANTU_DEBUG_ASSERT(this->size() == 3, "crossProduct is only defined in 3D (n=" << this->size() << ")"); AKANTU_DEBUG_ASSERT( this->size() == v1.size() && this->size() == v2.size(), "crossProduct is not a valid operation non matching size vectors"); Math::vectorProduct3(v1.storage(), v2.storage(), this->values); return *this; } inline Vector crossProduct(const Vector<T> & v) { Vector<T> tmp(this->size()); tmp.crossProduct(*this, v); return tmp; } /* ------------------------------------------------------------------------ */ inline void solve(const Matrix<T> & A, const Vector<T> & b) { AKANTU_DEBUG_ASSERT( this->size() == A.rows() && this->_size == A.cols(), "The size of the solution vector mismatches the size of the matrix"); AKANTU_DEBUG_ASSERT( this->_size == b._size, "The rhs vector has a mismatch in size with the matrix"); Math::solve(this->_size, A.storage(), this->values, b.storage()); } /* ------------------------------------------------------------------------ */ template <bool tr_A> inline void mul(const Matrix<T> & A, const Vector<T> & x, Real alpha = 1.0); /* ------------------------------------------------------------------------ */ inline Real norm() const { return parent::template norm<L_2>(); } template <NormType nt> inline Real norm() const { return parent::template norm<nt>(); } /* ------------------------------------------------------------------------ */ inline Vector<Real> & normalize() { Real n = norm(); operator/=(n); return *this; } /* ------------------------------------------------------------------------ */ /// norm of (*this - x) inline Real distance(const Vector<T> & y) const { Real * vx = this->values; Real * vy = y.storage(); Real sum_2 = 0; for (UInt i = 0; i < this->_size; ++i, ++vx, ++vy) sum_2 += (*vx - *vy) * (*vx - *vy); return sqrt(sum_2); } /* ------------------------------------------------------------------------ */ inline bool equal(const Vector<T> & v, Real tolerance = Math::getTolerance()) const { T * a = this->storage(); T * b = v.storage(); UInt i = 0; while (i < this->_size && (std::abs(*(a++) - *(b++)) < tolerance)) ++i; return i == this->_size; } /* ------------------------------------------------------------------------ */ inline short compare(const Vector<T> & v, Real tolerance = Math::getTolerance()) const { T * a = this->storage(); T * b = v.storage(); for (UInt i(0); i < this->_size; ++i, ++a, ++b) { if (std::abs(*a - *b) > tolerance) return (((*a - *b) > tolerance) ? 1 : -1); } return 0; } /* ------------------------------------------------------------------------ */ inline bool operator==(const Vector<T> & v) const { return equal(v); } inline bool operator!=(const Vector<T> & v) const { return !operator==(v); } inline bool operator<(const Vector<T> & v) const { return compare(v) == -1; } inline bool operator>(const Vector<T> & v) const { return compare(v) == 1; } /* ------------------------------------------------------------------------ */ /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << "["; for (UInt i = 0; i < this->_size; ++i) { if (i != 0) stream << ", "; stream << this->values[i]; } stream << "]"; } // friend class ::akantu::Array<T>; }; using RVector = Vector<Real>; /* ------------------------------------------------------------------------ */ template <> inline bool Vector<UInt>::equal(const Vector<UInt> & v, __attribute__((unused)) Real tolerance) const { UInt * a = this->storage(); UInt * b = v.storage(); UInt i = 0; while (i < this->_size && (*(a++) == *(b++))) ++i; return i == this->_size; } /* ------------------------------------------------------------------------ */ /* Matrix */ /* ------------------------------------------------------------------------ */ template <typename T> class Matrix : public TensorStorage<T, 2, Matrix<T>> { using parent = TensorStorage<T, 2, Matrix<T>>; public: using value_type = typename parent::value_type; using proxy = MatrixProxy<T>; public: Matrix() : parent() {} Matrix(UInt m, UInt n, const T & def = T()) : parent(m, n, 0, def) {} Matrix(T * data, UInt m, UInt n) : parent(data, m, n, 0) {} Matrix(const Matrix & src, bool deep_copy = true) : parent(src, deep_copy) {} Matrix(const MatrixProxy<T> & src) : parent(src) {} Matrix(std::initializer_list<std::initializer_list<T>> list) { static_assert(std::is_trivially_copyable<T>{}, "Cannot create a tensor on non trivial types"); std::size_t n = 0; std::size_t m = list.size(); for (auto row : list) { n = std::max(n, row.size()); } DimHelper<2>::setDims(m, n, 0, this->n); this->computeSize(); this->values = new T[this->_size]; this->set(0); UInt i = 0, j = 0; for (auto & row : list) { for (auto & val : row) { at(i, j++) = val; } ++i; j = 0; } } ~Matrix() override = default; /* ------------------------------------------------------------------------ */ inline Matrix & operator=(const Matrix & src) { parent::operator=(src); return *this; } public: /* ---------------------------------------------------------------------- */ UInt rows() const { return this->n[0]; } UInt cols() const { return this->n[1]; } /* ---------------------------------------------------------------------- */ inline T & at(UInt i, UInt j) { AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])), "Access out of the matrix! " << "Index (" << i << ", " << j << ") is out of the matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return *(this->values + i + j * this->n[0]); } inline const T & at(UInt i, UInt j) const { AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])), "Access out of the matrix! " << "Index (" << i << ", " << j << ") is out of the matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return *(this->values + i + j * this->n[0]); } /* ------------------------------------------------------------------------ */ inline T & operator()(UInt i, UInt j) { return this->at(i, j); } inline const T & operator()(UInt i, UInt j) const { return this->at(i, j); } /// give a line vector wrapped on the column i inline VectorProxy<T> operator()(UInt j) { AKANTU_DEBUG_ASSERT(j < this->n[1], "Access out of the matrix! " << "You are trying to access the column vector " << j << " in a matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return VectorProxy<T>(this->values + j * this->n[0], this->n[0]); } inline const VectorProxy<T> operator()(UInt j) const { AKANTU_DEBUG_ASSERT(j < this->n[1], "Access out of the matrix! " << "You are trying to access the column vector " << j << " in a matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return VectorProxy<T>(this->values + j * this->n[0], this->n[0]); } inline void block(const Matrix & block, UInt pos_i, UInt pos_j) { AKANTU_DEBUG_ASSERT(pos_i + block.rows() <= rows(), "The block size or position are not correct"); AKANTU_DEBUG_ASSERT(pos_i + block.cols() <= cols(), "The block size or position are not correct"); for (UInt i = 0; i < block.rows(); ++i) for (UInt j = 0; j < block.cols(); ++j) this->at(i + pos_i, j + pos_j) = block(i, j); } inline Matrix block(UInt pos_i, UInt pos_j, UInt block_rows, UInt block_cols) const { AKANTU_DEBUG_ASSERT(pos_i + block_rows <= rows(), "The block size or position are not correct"); AKANTU_DEBUG_ASSERT(pos_i + block_cols <= cols(), "The block size or position are not correct"); Matrix block(block_rows, block_cols); for (UInt i = 0; i < block_rows; ++i) for (UInt j = 0; j < block_cols; ++j) block(i, j) = this->at(i + pos_i, j + pos_j); return block; } inline T & operator[](UInt idx) { return *(this->values + idx); }; inline const T & operator[](UInt idx) const { return *(this->values + idx); }; /* ---------------------------------------------------------------------- */ inline Matrix operator*(const Matrix & B) { Matrix C(this->rows(), B.cols()); C.mul<false, false>(*this, B); return C; } /* ----------------------------------------------------------------------- */ inline Matrix & operator*=(const T & x) { return parent::operator*=(x); } inline Matrix & operator*=(const Matrix & B) { Matrix C(*this); this->mul<false, false>(C, B); return *this; } /* ---------------------------------------------------------------------- */ template <bool tr_A, bool tr_B> inline void mul(const Matrix & A, const Matrix & B, T alpha = 1.0) { UInt k = A.cols(); if (tr_A) k = A.rows(); #ifndef AKANTU_NDEBUG if (tr_B) { AKANTU_DEBUG_ASSERT(k == B.cols(), "matrices to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->cols() == B.rows(), "matrices to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(k == B.rows(), "matrices to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->cols() == B.cols(), "matrices to multiply have no fit dimensions"); } if (tr_A) { AKANTU_DEBUG_ASSERT(this->rows() == A.cols(), "matrices to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(this->rows() == A.rows(), "matrices to multiply have no fit dimensions"); } #endif // AKANTU_NDEBUG Math::matMul<tr_A, tr_B>(this->rows(), this->cols(), k, alpha, A.storage(), B.storage(), 0., this->storage()); } /* ---------------------------------------------------------------------- */ inline void outerProduct(const Vector<T> & A, const Vector<T> & B) { AKANTU_DEBUG_ASSERT( A.size() == this->rows() && B.size() == this->cols(), "A and B are not compatible with the size of the matrix"); for (UInt i = 0; i < this->rows(); ++i) { for (UInt j = 0; j < this->cols(); ++j) { this->values[i + j * this->rows()] += A[i] * B[j]; } } } private: class EigenSorter { public: EigenSorter(const Vector<T> & eigs) : eigs(eigs) {} bool operator()(const UInt & a, const UInt & b) const { return (eigs(a) > eigs(b)); } private: const Vector<T> & eigs; }; public: /* ---------------------------------------------------------------------- */ inline void eig(Vector<T> & eigenvalues, Matrix<T> & eigenvectors) const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "eig is not a valid operation on a rectangular matrix"); AKANTU_DEBUG_ASSERT(eigenvalues.size() == this->cols(), "eigenvalues should be of size " << this->cols() << "."); #ifndef AKANTU_NDEBUG if (eigenvectors.storage() != nullptr) AKANTU_DEBUG_ASSERT((eigenvectors.rows() == eigenvectors.cols()) && (eigenvectors.rows() == this->cols()), "Eigenvectors needs to be a square matrix of size " << this->cols() << " x " << this->cols() << "."); #endif Matrix<T> tmp = *this; Vector<T> tmp_eigs(eigenvalues.size()); Matrix<T> tmp_eig_vects(eigenvectors.rows(), eigenvectors.cols()); if (tmp_eig_vects.rows() == 0 || tmp_eig_vects.cols() == 0) Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage()); else Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage(), tmp_eig_vects.storage()); Vector<UInt> perm(eigenvalues.size()); for (UInt i = 0; i < perm.size(); ++i) perm(i) = i; std::sort(perm.storage(), perm.storage() + perm.size(), EigenSorter(tmp_eigs)); for (UInt i = 0; i < perm.size(); ++i) eigenvalues(i) = tmp_eigs(perm(i)); if (tmp_eig_vects.rows() != 0 && tmp_eig_vects.cols() != 0) for (UInt i = 0; i < perm.size(); ++i) { for (UInt j = 0; j < eigenvectors.rows(); ++j) { eigenvectors(j, i) = tmp_eig_vects(j, perm(i)); } } } /* ---------------------------------------------------------------------- */ inline void eig(Vector<T> & eigenvalues) const { Matrix<T> empty; eig(eigenvalues, empty); } /* ---------------------------------------------------------------------- */ inline void eye(T alpha = 1.) { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "eye is not a valid operation on a rectangular matrix"); this->clear(); for (UInt i = 0; i < this->cols(); ++i) { this->values[i + i * this->rows()] = alpha; } } /* ---------------------------------------------------------------------- */ static inline Matrix<T> eye(UInt m, T alpha = 1.) { Matrix<T> tmp(m, m); tmp.eye(alpha); return tmp; } /* ---------------------------------------------------------------------- */ inline T trace() const { AKANTU_DEBUG_ASSERT( this->cols() == this->rows(), "trace is not a valid operation on a rectangular matrix"); T trace = 0.; for (UInt i = 0; i < this->rows(); ++i) { trace += this->values[i + i * this->rows()]; } return trace; } /* ---------------------------------------------------------------------- */ inline Matrix transpose() const { Matrix tmp(this->cols(), this->rows()); for (UInt i = 0; i < this->rows(); ++i) { for (UInt j = 0; j < this->cols(); ++j) { tmp(j, i) = operator()(i, j); } } return tmp; } /* ---------------------------------------------------------------------- */ inline void inverse(const Matrix & A) { AKANTU_DEBUG_ASSERT(A.cols() == A.rows(), "inv is not a valid operation on a rectangular matrix"); AKANTU_DEBUG_ASSERT(this->cols() == A.cols(), "the matrix should have the same size as its inverse"); if (this->cols() == 1) *this->values = 1. / *A.storage(); else if (this->cols() == 2) Math::inv2(A.storage(), this->values); else if (this->cols() == 3) Math::inv3(A.storage(), this->values); else Math::inv(this->cols(), A.storage(), this->values); } inline Matrix inverse() { Matrix inv(this->rows(), this->cols()); inv.inverse(*this); return inv; } /* --------------------------------------------------------------------- */ inline T det() const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "inv is not a valid operation on a rectangular matrix"); if (this->cols() == 1) return *(this->values); else if (this->cols() == 2) return Math::det2(this->values); else if (this->cols() == 3) return Math::det3(this->values); else return Math::det(this->cols(), this->values); } /* --------------------------------------------------------------------- */ inline T doubleDot(const Matrix<T> & other) const { AKANTU_DEBUG_ASSERT( this->cols() == this->rows(), "doubleDot is not a valid operation on a rectangular matrix"); if (this->cols() == 1) return *(this->values) * *(other.storage()); else if (this->cols() == 2) return Math::matrixDoubleDot22(this->values, other.storage()); else if (this->cols() == 3) return Math::matrixDoubleDot33(this->values, other.storage()); else AKANTU_ERROR("doubleDot is not defined for other spatial dimensions" << " than 1, 2 or 3."); return T(); } /* ---------------------------------------------------------------------- */ /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << "["; for (UInt i = 0; i < this->n[0]; ++i) { if (i != 0) stream << ", "; stream << "["; for (UInt j = 0; j < this->n[1]; ++j) { if (j != 0) stream << ", "; stream << operator()(i, j); } stream << "]"; } stream << "]"; }; }; /* ------------------------------------------------------------------------ */ template <typename T> template <bool tr_A> inline void Vector<T>::mul(const Matrix<T> & A, const Vector<T> & x, Real alpha) { #ifndef AKANTU_NDEBUG UInt n = x.size(); if (tr_A) { AKANTU_DEBUG_ASSERT(n == A.rows(), "matrix and vector to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->size() == A.cols(), "matrix and vector to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(n == A.cols(), "matrix and vector to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->size() == A.rows(), "matrix and vector to multiply have no fit dimensions"); } #endif Math::matVectMul<tr_A>(A.rows(), A.cols(), alpha, A.storage(), x.storage(), 0., this->storage()); } /* -------------------------------------------------------------------------- */ template <typename T> inline std::ostream & operator<<(std::ostream & stream, const Matrix<T> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ template <typename T> inline std::ostream & operator<<(std::ostream & stream, const Vector<T> & _this) { _this.printself(stream); return stream; } /* ------------------------------------------------------------------------ */ /* Tensor3 */ /* ------------------------------------------------------------------------ */ template <typename T> class Tensor3 : public TensorStorage<T, 3, Tensor3<T>> { using parent = TensorStorage<T, 3, Tensor3<T>>; public: using value_type = typename parent::value_type; using proxy = Tensor3Proxy<T>; public: Tensor3() : parent(){}; Tensor3(UInt m, UInt n, UInt p, const T & def = T()) : parent(m, n, p, def) {} Tensor3(T * data, UInt m, UInt n, UInt p) : parent(data, m, n, p) {} Tensor3(const Tensor3 & src, bool deep_copy = true) : parent(src, deep_copy) {} Tensor3(const proxy & src) : parent(src) {} public: /* ------------------------------------------------------------------------ */ inline Tensor3 & operator=(const Tensor3 & src) { parent::operator=(src); return *this; } /* ---------------------------------------------------------------------- */ inline T & operator()(UInt i, UInt j, UInt k) { AKANTU_DEBUG_ASSERT( (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the element " << "(" << i << ", " << j << ", " << k << ") in a tensor of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return *(this->values + (k * this->n[0] + i) * this->n[1] + j); } inline const T & operator()(UInt i, UInt j, UInt k) const { AKANTU_DEBUG_ASSERT( (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the element " << "(" << i << ", " << j << ", " << k << ") in a tensor of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return *(this->values + (k * this->n[0] + i) * this->n[1] + j); } inline MatrixProxy<T> operator()(UInt k) { AKANTU_DEBUG_ASSERT((k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the slice " << k << " in a tensor3 of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } inline const MatrixProxy<T> operator()(UInt k) const { AKANTU_DEBUG_ASSERT((k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the slice " << k << " in a tensor3 of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } inline MatrixProxy<T> operator[](UInt k) { return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } inline const MatrixProxy<T> operator[](UInt k) const { return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } }; /* -------------------------------------------------------------------------- */ // support operations for the creation of other vectors /* -------------------------------------------------------------------------- */ template <typename T> Vector<T> operator*(const T & scalar, const Vector<T> & a) { Vector<T> r(a); r *= scalar; return r; } template <typename T> Vector<T> operator*(const Vector<T> & a, const T & scalar) { Vector<T> r(a); r *= scalar; return r; } template <typename T> Vector<T> operator/(const Vector<T> & a, const T & scalar) { Vector<T> r(a); r /= scalar; return r; } template <typename T> Vector<T> operator*(const Vector<T> & a, const Vector<T> & b) { Vector<T> r(a); r *= b; return r; } template <typename T> Vector<T> operator+(const Vector<T> & a, const Vector<T> & b) { Vector<T> r(a); r += b; return r; } template <typename T> Vector<T> operator-(const Vector<T> & a, const Vector<T> & b) { Vector<T> r(a); r -= b; return r; } template <typename T> Vector<T> operator*(const Matrix<T> & A, const Vector<T> & b) { Vector<T> r(b.size()); r.template mul<false>(A, b); return r; } /* -------------------------------------------------------------------------- */ template <typename T> Matrix<T> operator*(const T & scalar, const Matrix<T> & a) { Matrix<T> r(a); r *= scalar; return r; } template <typename T> Matrix<T> operator*(const Matrix<T> & a, const T & scalar) { Matrix<T> r(a); r *= scalar; return r; } template <typename T> Matrix<T> operator/(const Matrix<T> & a, const T & scalar) { Matrix<T> r(a); r /= scalar; return r; } template <typename T> Matrix<T> operator+(const Matrix<T> & a, const Matrix<T> & b) { Matrix<T> r(a); r += b; return r; } template <typename T> Matrix<T> operator-(const Matrix<T> & a, const Matrix<T> & b) { Matrix<T> r(a); r -= b; return r; } } // namespace akantu #endif /* __AKANTU_AKA_TYPES_HH__ */ diff --git a/src/common/aka_visitor.hh b/src/common/aka_visitor.hh index b16fe120e..ad43690ff 100644 --- a/src/common/aka_visitor.hh +++ b/src/common/aka_visitor.hh @@ -1,164 +1,164 @@ /** * @file aka_visitor.hh * * @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Jun 19 2017 * * @brief Objects that support the visitor design pattern * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_VISITOR_HH__ #define __AKANTU_VISITOR_HH__ #include "aka_typelist.hh" namespace akantu { /////////////////////////////////////////////////////////////////////////// // visitor class template, adapted from the Andrei Alexandrescu's // "Modern C++ Design" enum Visit_type { Mutable, Immutable }; template <class T, typename R = void, Visit_type = Mutable> class StrictVisitor; template <class T, typename R> class StrictVisitor<T, R, Mutable> { public: typedef R ReturnType; typedef T ParamType; virtual ~StrictVisitor() {} virtual ReturnType Visit(ParamType &) = 0; }; template <class T, typename R> class StrictVisitor<T, R, Immutable> { public: typedef R ReturnType; typedef const T ParamType; virtual ~StrictVisitor() {} virtual ReturnType Visit(ParamType &) = 0; }; /// class template StrictVisitor (specialization) template <class Head, class Tail, typename R> class StrictVisitor<Typelist<Head, Tail>, R, Mutable> : public StrictVisitor<Head, R, Mutable>, public StrictVisitor<Tail, R, Mutable> { public: typedef R ReturnType; typedef Head ParamType; // using StrictVisitor<Head, R>::Visit; // using StrictVisitor<Tail, R>::Visit; }; template <class Head, typename R> class StrictVisitor<Typelist<Head, Null_type>, R, Mutable> : public StrictVisitor<Head, R, Mutable> { public: typedef R ReturnType; typedef Head ParamType; using StrictVisitor<Head, R, Mutable>::Visit; }; template <class Head, class Tail, typename R> class StrictVisitor<Typelist<Head, Tail>, R, Immutable> : public StrictVisitor<Head, R, Immutable>, public StrictVisitor<Tail, R, Immutable> { public: typedef R ReturnType; typedef Head ParamType; // using StrictVisitor<Head, R>::Visit; // using StrictVisitor<Tail, R>::Visit; }; template <class Head, typename R> class StrictVisitor<Typelist<Head, Null_type>, R, Immutable> : public StrictVisitor<Head, R, Immutable> { public: typedef R ReturnType; typedef Head ParamType; using StrictVisitor<Head, R, Immutable>::Visit; }; //////////////////////////////////////////////////////////////////////////////// // class template NonStrictVisitor // Implements non-strict visitation (you can implement only part of the Visit // functions) // template <class R> struct DefaultFunctor { template <class T> R operator()(T &) { return R(); } }; template <class T, typename R = void, Visit_type V = Mutable, class F = DefaultFunctor<R>> class BaseVisitorImpl; template <class Head, class Tail, typename R, Visit_type V, class F> class BaseVisitorImpl<Typelist<Head, Tail>, R, V, F> : public StrictVisitor<Head, R, V>, public BaseVisitorImpl<Tail, R, V, F> { public: typedef typename StrictVisitor<Head, R, V>::ParamType ParamType; virtual R Visit(ParamType & h) { return F()(h); } }; template <class Head, typename R, Visit_type V, class F> class BaseVisitorImpl<Typelist<Head, Null_type>, R, V, F> : public StrictVisitor<Head, R, V> { public: typedef typename StrictVisitor<Head, R, V>::ParamType ParamType; virtual R Visit(ParamType & h) { return F()(h); } }; /// Visitor template <class R> struct Strict {}; template <typename R, class TList, Visit_type V = Mutable, template <class> class FunctorPolicy = DefaultFunctor> class Visitor : public BaseVisitorImpl<TList, R, V, FunctorPolicy<R>> { public: typedef R ReturnType; template <class Visited> ReturnType GenericVisit(Visited & host) { StrictVisitor<Visited, ReturnType, V> & subObj = *this; return subObj.Visit(host); } }; template <typename R, class TList, Visit_type V> class Visitor<R, TList, V, Strict> : public StrictVisitor<TList, R, V> { public: typedef R ReturnType; template <class Visited> ReturnType GenericVisit(Visited & host) { StrictVisitor<Visited, ReturnType, V> & subObj = *this; return subObj.Visit(host); } }; } // akantu #endif /* __AKANTU_VISITOR_HH__ */ diff --git a/src/common/aka_voigthelper.cc b/src/common/aka_voigthelper.cc index 13bdbbb3b..ddf66d62e 100644 --- a/src/common/aka_voigthelper.cc +++ b/src/common/aka_voigthelper.cc @@ -1,68 +1,68 @@ /** * @file aka_voigthelper.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Till Junge <till.junge@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Dec 20 2013 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Jun 19 2017 * * @brief Voigt indices * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_voigthelper.hh" #include "aka_common.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* clang-format off */ template <> const UInt VoigtHelper<1>::mat[][1] = {{0}}; template <> const UInt VoigtHelper<2>::mat[][2] = {{0, 2}, {3, 1}}; template <> const UInt VoigtHelper<3>::mat[][3] = {{0, 5, 4}, {8, 1, 3}, {7, 6, 2}}; template <> const UInt VoigtHelper<1>::vec[][2] = {{0, 0}}; template <> const UInt VoigtHelper<2>::vec[][2] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; template <> const UInt VoigtHelper<3>::vec[][2] = {{0, 0}, {1, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}, {2, 1}, {2, 0}, {1, 0}}; template <> const Real VoigtHelper<1>::factors[] = {1.}; template <> const Real VoigtHelper<2>::factors[] = {1., 1., 2.}; template <> const Real VoigtHelper<3>::factors[] = {1., 1., 1., 2., 2., 2.}; /* clang-format on */ } // akantu diff --git a/src/common/aka_voigthelper.hh b/src/common/aka_voigthelper.hh index 25a0cd79b..ac3dfd893 100644 --- a/src/common/aka_voigthelper.hh +++ b/src/common/aka_voigthelper.hh @@ -1,79 +1,79 @@ - /** * @file aka_voigthelper.hh * + * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Till Junge <till.junge@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Dec 20 2013 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Mon Jan 29 2018 * * @brief Helper file for Voigt notation * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKA_VOIGTHELPER_HH__ #define __AKA_VOIGTHELPER_HH__ #include "aka_common.hh" #include "aka_types.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim> class VoigtHelper { static_assert(dim != 0, "Cannot be 0D"); public: /// transfer the B matrix to a Voigt notation B matrix inline static void transferBMatrixToSymVoigtBMatrix( const Matrix<Real> & B, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element); /// transfer the BNL matrix to a Voigt notation B matrix (See Bathe et al. /// IJNME vol 9, 1975) inline static void transferBMatrixToBNL(const Matrix<Real> & B, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element); /// transfer the BL2 matrix to a Voigt notation B matrix (See Bathe et al. /// IJNME vol 9, 1975) inline static void transferBMatrixToBL2(const Matrix<Real> & B, const Matrix<Real> & grad_u, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element); public: static constexpr UInt size{(dim * (dim - 1)) / 2 + dim}; // matrix of vector index I as function of tensor indices i,j static const UInt mat[dim][dim]; // array of matrix indices ij as function of vector index I static const UInt vec[dim * dim][2]; // factors to multiply the strain by for voigt notation static const Real factors[size]; }; } // akantu #include "aka_voigthelper_tmpl.hh" #endif diff --git a/src/common/aka_voigthelper_tmpl.hh b/src/common/aka_voigthelper_tmpl.hh index 1c7cec16d..0582da0b8 100644 --- a/src/common/aka_voigthelper_tmpl.hh +++ b/src/common/aka_voigthelper_tmpl.hh @@ -1,149 +1,179 @@ +/** + * @file aka_voigthelper_tmpl.hh + * + * @author Nicolas Richart <nicolas.richart@epfl.ch> + * + * @date creation: Fri Dec 20 2013 + * @date last modification: Wed Dec 06 2017 + * + * @brief implementation of the voight helper + * + * @section LICENSE + * + * Copyright (©) 2014-2018 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 <http://www.gnu.org/licenses/>. + * + */ + /** * @file aka_voigthelper_tmpl.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Wed Nov 16 12:22:58 2016 */ /* -------------------------------------------------------------------------- */ #include "aka_voigthelper.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_VOIGTHELPER_TMPL_HH__ #define __AKANTU_AKA_VOIGTHELPER_TMPL_HH__ namespace akantu { template <UInt dim> constexpr UInt VoigtHelper<dim>::size; /* -------------------------------------------------------------------------- */ template <UInt dim> inline void VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( const Matrix<Real> & B, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element) { Bvoigt.clear(); for (UInt i = 0; i < dim; ++i) for (UInt n = 0; n < nb_nodes_per_element; ++n) Bvoigt(i, i + n * dim) = B(i, n); if (dim == 2) { /// in 2D, fill the @f$ [\frac{\partial N_i}{\partial x}, \frac{\partial /// N_i}{\partial y}]@f$ row for (UInt n = 0; n < nb_nodes_per_element; ++n) { Bvoigt(2, 1 + n * 2) = B(0, n); Bvoigt(2, 0 + n * 2) = B(1, n); } } if (dim == 3) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { Real dndx = B(0, n); Real dndy = B(1, n); Real dndz = B(2, n); /// in 3D, fill the @f$ [0, \frac{\partial N_i}{\partial y}, /// \frac{N_i}{\partial z}]@f$ row Bvoigt(3, 1 + n * 3) = dndz; Bvoigt(3, 2 + n * 3) = dndy; /// in 3D, fill the @f$ [\frac{\partial N_i}{\partial x}, 0, /// \frac{N_i}{\partial z}]@f$ row Bvoigt(4, 0 + n * 3) = dndz; Bvoigt(4, 2 + n * 3) = dndx; /// in 3D, fill the @f$ [\frac{\partial N_i}{\partial x}, /// \frac{N_i}{\partial y}, 0]@f$ row Bvoigt(5, 0 + n * 3) = dndy; Bvoigt(5, 1 + n * 3) = dndx; } } } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void VoigtHelper<dim>::transferBMatrixToBNL(const Matrix<Real> & B, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element) { Bvoigt.clear(); // see Finite element formulations for large deformation dynamic analysis, // Bathe et al. IJNME vol 9, 1975, page 364 B_{NL} for (UInt i = 0; i < dim; ++i) { for (UInt m = 0; m < nb_nodes_per_element; ++m) { for (UInt n = 0; n < dim; ++n) { // std::cout << B(n, m) << std::endl; Bvoigt(i * dim + n, m * dim + i) = B(n, m); } } } // TODO: Verify the 2D and 1D case } /* -------------------------------------------------------------------------- */ template <> inline void VoigtHelper<1>::transferBMatrixToBL2(const Matrix<Real> & B, const Matrix<Real> & grad_u, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element) { Bvoigt.clear(); for (UInt j = 0; j < nb_nodes_per_element; ++j) for (UInt k = 0; k < 2; ++k) Bvoigt(0, j * 2 + k) = grad_u(k, 0) * B(0, j); } /* -------------------------------------------------------------------------- */ template <> inline void VoigtHelper<3>::transferBMatrixToBL2(const Matrix<Real> & B, const Matrix<Real> & grad_u, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element) { Bvoigt.clear(); for (UInt i = 0; i < 3; ++i) for (UInt j = 0; j < nb_nodes_per_element; ++j) for (UInt k = 0; k < 3; ++k) Bvoigt(i, j * 3 + k) = grad_u(k, i) * B(i, j); for (UInt i = 3; i < 6; ++i) { for (UInt j = 0; j < nb_nodes_per_element; ++j) { for (UInt k = 0; k < 3; ++k) { UInt aux = i - 3; for (UInt m = 0; m < 3; ++m) { if (m != aux) { UInt index1 = m; UInt index2 = 3 - m - aux; Bvoigt(i, j * 3 + k) += grad_u(k, index1) * B(index2, j); } } } } } } /* -------------------------------------------------------------------------- */ template <> inline void VoigtHelper<2>::transferBMatrixToBL2(const Matrix<Real> & B, const Matrix<Real> & grad_u, Matrix<Real> & Bvoigt, UInt nb_nodes_per_element) { Bvoigt.clear(); for (UInt i = 0; i < 2; ++i) for (UInt j = 0; j < nb_nodes_per_element; ++j) for (UInt k = 0; k < 2; ++k) Bvoigt(i, j * 2 + k) = grad_u(k, i) * B(i, j); for (UInt j = 0; j < nb_nodes_per_element; ++j) { for (UInt k = 0; k < 2; ++k) { for (UInt m = 0; m < 2; ++m) { UInt index1 = m; UInt index2 = (2 - 1) - m; Bvoigt(2, j * 2 + k) += grad_u(k, index1) * B(index2, j); } } } } } // akantu #endif /* __AKANTU_AKA_VOIGTHELPER_TMPL_HH__ */ diff --git a/src/common/aka_warning.hh b/src/common/aka_warning.hh index 21db7d188..13dd7c52e 100644 --- a/src/common/aka_warning.hh +++ b/src/common/aka_warning.hh @@ -1,25 +1,55 @@ +/** + * @file aka_warning.hh + * + * @author Nicolas Richart <nicolas.richart@epfl.ch> + * + * @date creation: Mon Nov 14 2016 + * @date last modification: Fri Dec 02 2016 + * + * @brief file to include to remove some warnings + * + * @section LICENSE + * + * Copyright (©) 2016-2018 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 <http://www.gnu.org/licenses/>. + * + */ + // Intel warnings #if defined(__INTEL_COMPILER) #if defined(AKANTU_WARNING_IGNORE_UNUSED_PARAMETER) #endif // Clang Warnings #elif defined(__clang__) // test clang to be sure that when we test for gnu it - // is only gnu +// is only gnu #pragma clang diagnostic push #if defined(AKANTU_WARNING_IGNORE_UNUSED_PARAMETER) #pragma clang diagnostic ignored "-Wunused-parameter" #endif // GCC warnings #elif (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40600 #pragma GCC diagnostic push #endif #if defined(AKANTU_WARNING_IGNORE_UNUSED_PARAMETER) #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif diff --git a/src/common/aka_warning_restore.hh b/src/common/aka_warning_restore.hh index 6f123debb..0d142a18f 100644 --- a/src/common/aka_warning_restore.hh +++ b/src/common/aka_warning_restore.hh @@ -1,16 +1,46 @@ +/** + * @file aka_warning_restore.hh + * + * @author Nicolas Richart <nicolas.richart@epfl.ch> + * + * @date creation: Mon Nov 14 2016 + * @date last modification: Fri Dec 02 2016 + * + * @brief file to include to reactivate the previously deactivatied warnings + * + * @section LICENSE + * + * Copyright (©) 2016-2018 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 <http://www.gnu.org/licenses/>. + * + */ + #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it - // is only gnu +// is only gnu #pragma clang diagnostic pop #elif defined(__GNUG__) #if GCC_VERSION > 40600 #pragma GCC diagnostic pop #else #if defined(AKANTU_WARNING_IGNORE_UNUSED_PARAMETER) #pragma GCC diagnostic warning "-Wunused-parameter" #endif #endif #endif #undef AKANTU_WARNING_IGNORE_UNUSED_PARAMETER diff --git a/src/fe_engine/cohesive_element.hh b/src/fe_engine/cohesive_element.hh index e6ab33817..143bf3fe9 100644 --- a/src/fe_engine/cohesive_element.hh +++ b/src/fe_engine/cohesive_element.hh @@ -1,91 +1,90 @@ /** * @file cohesive_element.hh * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Wed Oct 11 2017 * * @brief Generates the cohesive element structres (defined in * element_class.hh) * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COHESIVE_ELEMENT_HH__ #define __AKANTU_COHESIVE_ELEMENT_HH__ namespace akantu { AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_2d_4, _gt_cohesive_2d_4, _itp_lagrange_segment_2, _ek_cohesive, 2, _git_segment, 2); AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_2d_6, _gt_cohesive_2d_6, _itp_lagrange_segment_3, _ek_cohesive, 2, _git_segment, 3); AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_1d_2, _gt_cohesive_1d_2, _itp_lagrange_point_1, _ek_cohesive, 1, _git_point, 1); AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_3d_6, _gt_cohesive_3d_6, _itp_lagrange_triangle_3, _ek_cohesive, 3, _git_triangle, 2); AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_3d_12, _gt_cohesive_3d_12, _itp_lagrange_triangle_6, _ek_cohesive, 3, _git_triangle, 3); AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_3d_8, _gt_cohesive_3d_8, _itp_lagrange_quadrangle_4, _ek_cohesive, 3, _git_segment, 2); AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_3d_16, _gt_cohesive_3d_16, _itp_serendip_quadrangle_8, _ek_cohesive, 3, _git_segment, 3); template <ElementType> struct CohesiveFacetProperty { static const ElementType cohesive_type = _not_defined; }; #define AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(ftype, ctype) \ template <> struct CohesiveFacetProperty<ftype> { \ static const ElementType cohesive_type = ctype; \ } AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(_point_1, _cohesive_1d_2); AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(_segment_2, _cohesive_2d_4); AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(_segment_3, _cohesive_2d_6); AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(_triangle_3, _cohesive_3d_6); AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(_triangle_6, _cohesive_3d_12); AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(_quadrangle_4, _cohesive_3d_8); AKANTU_DEFINE_COHESIVE_FACET_PROPERTY(_quadrangle_8, _cohesive_3d_16); } // namespace akantu #endif /* __AKANTU_COHESIVE_ELEMENT_HH__ */ diff --git a/src/fe_engine/element.hh b/src/fe_engine/element.hh index fd5f4d668..02b8796a4 100644 --- a/src/fe_engine/element.hh +++ b/src/fe_engine/element.hh @@ -1,112 +1,113 @@ /** * @file element.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Sat Jul 11 2015 + * @date last modification: Tue Jan 23 2018 * * @brief Element helper class * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_HH__ #define __AKANTU_ELEMENT_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Element */ /* -------------------------------------------------------------------------- */ class Element { public: ElementType type; UInt element; GhostType ghost_type; // ElementKind kind; // ElementType type{_not_defined}; // UInt element{0}; // GhostType ghost_type{_not_ghost}; // ElementKind kind{_ek_regular}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: inline ElementKind kind() const; inline bool operator==(const Element & elem) const { return std::tie(type, element, ghost_type) == std::tie(elem.type, elem.element, elem.ghost_type); } inline bool operator!=(const Element & elem) const { return std::tie(type, element, ghost_type) != std::tie(elem.type, elem.element, elem.ghost_type); } // inline bool operator==(const Element & elem) const { // return ((element == elem.element) && (type == elem.type) && // (ghost_type == elem.ghost_type) && (kind == elem.kind)); // } // inline bool operator!=(const Element & elem) const { // return ((element != elem.element) || (type != elem.type) || // (ghost_type != elem.ghost_type) || (kind != elem.kind)); // } inline bool operator<(const Element & rhs) const; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Element & _this) { stream << "Element [" << _this.type << ", " << _this.element << ", " << _this.ghost_type << "]"; return stream; } namespace { const Element ElementNull{_not_defined, UInt(-1), _casper}; // Element{_not_defined, 0, _casper, _ek_not_defined}; } /* -------------------------------------------------------------------------- */ inline bool Element::operator<(const Element & rhs) const { // bool res = // (rhs == ElementNull) || // ((this->kind < rhs.kind) || // ((this->kind == rhs.kind) && // ((this->ghost_type < rhs.ghost_type) || // ((this->ghost_type == rhs.ghost_type) && // ((this->type < rhs.type) || // ((this->type == rhs.type) && (this->element < rhs.element))))))); return ((rhs == ElementNull) || std::tie(ghost_type, type, element) < std::tie(rhs.ghost_type, rhs.type, rhs.element)); } } // namespace akantu #endif /* __AKANTU_ELEMENT_HH__ */ diff --git a/src/fe_engine/element_class.hh b/src/fe_engine/element_class.hh index fb89b5709..feddcdc69 100644 --- a/src/fe_engine/element_class.hh +++ b/src/fe_engine/element_class.hh @@ -1,401 +1,400 @@ /** * @file element_class.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Declaration of the ElementClass main class and the * Integration and Interpolation elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_types.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_HH__ #define __AKANTU_ELEMENT_CLASS_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /// default element class structure template <ElementType element_type> struct ElementClassProperty { static const GeometricalType geometrical_type{_gt_not_defined}; static const InterpolationType interpolation_type{_itp_not_defined}; static const ElementKind element_kind{_ek_regular}; static const UInt spatial_dimension{0}; static const GaussIntegrationType gauss_integration_type{_git_not_defined}; static const UInt polynomial_degree{0}; }; /// Macro to generate the element class structures for different element types #define AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(elem_type, geom_type, \ interp_type, elem_kind, sp, \ gauss_int_type, min_int_order) \ template <> struct ElementClassProperty<elem_type> { \ static const GeometricalType geometrical_type{geom_type}; \ static const InterpolationType interpolation_type{interp_type}; \ static const ElementKind element_kind{elem_kind}; \ static const UInt spatial_dimension{sp}; \ static const GaussIntegrationType gauss_integration_type{gauss_int_type}; \ static const UInt polynomial_degree{min_int_order}; \ } /* -------------------------------------------------------------------------- */ /* Geometry */ /* -------------------------------------------------------------------------- */ /// Default GeometricalShape structure template <GeometricalType geometrical_type> struct GeometricalShape { static const GeometricalShapeType shape{_gst_point}; }; /// Templated GeometricalShape with function contains template <GeometricalShapeType shape> struct GeometricalShapeContains { /// Check if the point (vector in 2 and 3D) at natural coordinate coor template <class vector_type> static inline bool contains(const vector_type & coord); }; /// Macro to generate the GeometricalShape structures for different geometrical /// types #define AKANTU_DEFINE_SHAPE(geom_type, geom_shape) \ template <> struct GeometricalShape<geom_type> { \ static const GeometricalShapeType shape{geom_shape}; \ } AKANTU_DEFINE_SHAPE(_gt_hexahedron_20, _gst_square); AKANTU_DEFINE_SHAPE(_gt_hexahedron_8, _gst_square); AKANTU_DEFINE_SHAPE(_gt_pentahedron_15, _gst_prism); AKANTU_DEFINE_SHAPE(_gt_pentahedron_6, _gst_prism); AKANTU_DEFINE_SHAPE(_gt_point, _gst_point); AKANTU_DEFINE_SHAPE(_gt_quadrangle_4, _gst_square); AKANTU_DEFINE_SHAPE(_gt_quadrangle_8, _gst_square); AKANTU_DEFINE_SHAPE(_gt_segment_2, _gst_square); AKANTU_DEFINE_SHAPE(_gt_segment_3, _gst_square); AKANTU_DEFINE_SHAPE(_gt_tetrahedron_10, _gst_triangle); AKANTU_DEFINE_SHAPE(_gt_tetrahedron_4, _gst_triangle); AKANTU_DEFINE_SHAPE(_gt_triangle_3, _gst_triangle); AKANTU_DEFINE_SHAPE(_gt_triangle_6, _gst_triangle); /* -------------------------------------------------------------------------- */ template <GeometricalType geometrical_type> struct GeometricalElementProperty {}; template <ElementType element_type> struct ElementClassExtraGeometryProperties {}; /* -------------------------------------------------------------------------- */ /// Templated GeometricalElement with function getInradius template <GeometricalType geometrical_type, GeometricalShapeType shape = GeometricalShape<geometrical_type>::shape> class GeometricalElement { using geometrical_property = GeometricalElementProperty<geometrical_type>; public: /// compute the in-radius static inline Real getInradius(__attribute__((unused)) const Matrix<Real> & coord) { AKANTU_TO_IMPLEMENT(); } /// true if the natural coordinates are in the element template <class vector_type> static inline bool contains(const vector_type & coord); public: static AKANTU_GET_MACRO_NOT_CONST(SpatialDimension, geometrical_property::spatial_dimension, UInt); static AKANTU_GET_MACRO_NOT_CONST(NbNodesPerElement, geometrical_property::nb_nodes_per_element, UInt); static inline constexpr auto getNbFacetTypes() { return geometrical_property::nb_facet_types; }; static inline UInt getNbFacetsPerElement(UInt t); static inline UInt getNbFacetsPerElement(); static inline constexpr auto getFacetLocalConnectivityPerElement(UInt t = 0); }; /* -------------------------------------------------------------------------- */ /* Interpolation */ /* -------------------------------------------------------------------------- */ /// default InterpolationProperty structure template <InterpolationType interpolation_type> struct InterpolationProperty {}; /// Macro to generate the InterpolationProperty structures for different /// interpolation types #define AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(itp_type, itp_kind, \ nb_nodes, ndim) \ template <> struct InterpolationProperty<itp_type> { \ static constexpr InterpolationKind kind{itp_kind}; \ static constexpr UInt nb_nodes_per_element{nb_nodes}; \ static constexpr UInt natural_space_dimension{ndim}; \ } /* -------------------------------------------------------------------------- */ /// Generic (templated by the enum InterpolationType which specifies the order /// and the dimension of the interpolation) class handling the elemental /// interpolation template <InterpolationType interpolation_type, InterpolationKind kind = InterpolationProperty<interpolation_type>::kind> class InterpolationElement { public: using interpolation_property = InterpolationProperty<interpolation_type>; /// compute the shape values for a given set of points in natural coordinates static inline void computeShapes(const Matrix<Real> & natural_coord, Matrix<Real> & N); /// compute the shape values for a given point in natural coordinates template <class vector_type> static inline void computeShapes(const vector_type &, vector_type &) { AKANTU_TO_IMPLEMENT(); } /** * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of * shape functions along with variation of natural coordinates on a given set * of points in natural coordinates */ static inline void computeDNDS(const Matrix<Real> & natural_coord, Tensor3<Real> & dnds); /** * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of * shape functions along with * variation of natural coordinates on a given point in natural * coordinates */ template <class vector_type, class matrix_type> static inline void computeDNDS(const vector_type &, matrix_type &) { AKANTU_TO_IMPLEMENT(); } /// compute jacobian (or integration variable change factor) for a given point /// in the case of spatial_dimension != natural_space_dimension static inline void computeSpecialJacobian(const Matrix<Real> &, Real &) { AKANTU_TO_IMPLEMENT(); } /// interpolate a field given (arbitrary) natural coordinates static inline void interpolateOnNaturalCoordinates(const Vector<Real> & natural_coords, const Matrix<Real> & nodal_values, Vector<Real> & interpolated); /// interpolate a field given the shape functions on the interpolation point static inline void interpolate(const Matrix<Real> & nodal_values, const Vector<Real> & shapes, Vector<Real> & interpolated); /// interpolate a field given the shape functions on the interpolations points static inline void interpolate(const Matrix<Real> & nodal_values, const Matrix<Real> & shapes, Matrix<Real> & interpolated); /// compute the gradient of a given field on the given natural coordinates static inline void gradientOnNaturalCoordinates(const Vector<Real> & natural_coords, const Matrix<Real> & f, Matrix<Real> & gradient); public: static AKANTU_GET_MACRO_NOT_CONST( ShapeSize, InterpolationProperty<interpolation_type>::nb_nodes_per_element, UInt); static AKANTU_GET_MACRO_NOT_CONST( ShapeDerivativesSize, (InterpolationProperty<interpolation_type>::nb_nodes_per_element * InterpolationProperty<interpolation_type>::natural_space_dimension), UInt); static AKANTU_GET_MACRO_NOT_CONST( NaturalSpaceDimension, InterpolationProperty<interpolation_type>::natural_space_dimension, UInt); static AKANTU_GET_MACRO_NOT_CONST( NbNodesPerInterpolationElement, InterpolationProperty<interpolation_type>::nb_nodes_per_element, UInt); }; /* -------------------------------------------------------------------------- */ /* Integration */ /* -------------------------------------------------------------------------- */ template <GaussIntegrationType git_class, UInt nb_points> struct GaussIntegrationTypeData { /// quadrature points in natural coordinates static Real quad_positions[]; /// weights for the Gauss integration static Real quad_weights[]; }; template <ElementType type, UInt n = ElementClassProperty<type>::polynomial_degree> class GaussIntegrationElement { public: static UInt getNbQuadraturePoints(); static const Matrix<Real> getQuadraturePoints(); static const Vector<Real> getWeights(); }; /* -------------------------------------------------------------------------- */ /* ElementClass */ /* -------------------------------------------------------------------------- */ template <ElementType element_type, ElementKind element_kind = ElementClassProperty<element_type>::element_kind> class ElementClass : public GeometricalElement< ElementClassProperty<element_type>::geometrical_type>, public InterpolationElement< ElementClassProperty<element_type>::interpolation_type> { protected: using geometrical_element = GeometricalElement<ElementClassProperty<element_type>::geometrical_type>; using interpolation_element = InterpolationElement< ElementClassProperty<element_type>::interpolation_type>; using element_property = ElementClassProperty<element_type>; using interpolation_property = typename interpolation_element::interpolation_property; public: /** * compute @f$ J = \frac{\partial x_j}{\partial s_i} @f$ the variation of real * coordinates along with variation of natural coordinates on a given point in * natural coordinates */ static inline void computeJMat(const Matrix<Real> & dnds, const Matrix<Real> & node_coords, Matrix<Real> & J); /** * compute the Jacobian matrix by computing the variation of real coordinates * along with variation of natural coordinates on a given set of points in * natural coordinates */ static inline void computeJMat(const Tensor3<Real> & dnds, const Matrix<Real> & node_coords, Tensor3<Real> & J); /// compute the jacobians of a serie of natural coordinates static inline void computeJacobian(const Matrix<Real> & natural_coords, const Matrix<Real> & node_coords, Vector<Real> & jacobians); /// compute jacobian (or integration variable change factor) for a set of /// points static inline void computeJacobian(const Tensor3<Real> & J, Vector<Real> & jacobians); /// compute jacobian (or integration variable change factor) for a given point static inline void computeJacobian(const Matrix<Real> & J, Real & jacobians); /// compute shape derivatives (input is dxds) for a set of points static inline void computeShapeDerivatives(const Tensor3<Real> & J, const Tensor3<Real> & dnds, Tensor3<Real> & shape_deriv); /// compute shape derivatives (input is dxds) for a given point static inline void computeShapeDerivatives(const Matrix<Real> & J, const Matrix<Real> & dnds, Matrix<Real> & shape_deriv); /// compute the normal of a surface defined by the function f static inline void computeNormalsOnNaturalCoordinates(const Matrix<Real> & coord, Matrix<Real> & f, Matrix<Real> & normals); /// get natural coordinates from real coordinates static inline void inverseMap(const Vector<Real> & real_coords, const Matrix<Real> & node_coords, Vector<Real> & natural_coords, Real tolerance = 1e-10); /// get natural coordinates from real coordinates static inline void inverseMap(const Matrix<Real> & real_coords, const Matrix<Real> & node_coords, Matrix<Real> & natural_coords, Real tolerance = 1e-10); public: static AKANTU_GET_MACRO_NOT_CONST(Kind, element_kind, ElementKind); static constexpr AKANTU_GET_MACRO_NOT_CONST( SpatialDimension, ElementClassProperty<element_type>::spatial_dimension, UInt); using element_class_extra_geom_property = ElementClassExtraGeometryProperties<element_type>; static constexpr auto getP1ElementType() { return element_class_extra_geom_property::p1_type; } static constexpr auto getFacetType(UInt t = 0) { return element_class_extra_geom_property::facet_type[t]; } static constexpr auto getFacetTypes(); }; /* -------------------------------------------------------------------------- */ } // namespace akantu /* -------------------------------------------------------------------------- */ #include "geometrical_element_property.hh" #include "interpolation_element_tmpl.hh" /* -------------------------------------------------------------------------- */ #include "element_class_tmpl.hh" /* -------------------------------------------------------------------------- */ namespace akantu { #include "element_class_pentahedron_6_inline_impl.cc" /* keep order */ #include "element_class_hexahedron_20_inline_impl.cc" #include "element_class_hexahedron_8_inline_impl.cc" #include "element_class_pentahedron_15_inline_impl.cc" #include "element_class_point_1_inline_impl.cc" #include "element_class_quadrangle_4_inline_impl.cc" #include "element_class_quadrangle_8_inline_impl.cc" #include "element_class_segment_2_inline_impl.cc" #include "element_class_segment_3_inline_impl.cc" #include "element_class_tetrahedron_10_inline_impl.cc" #include "element_class_tetrahedron_4_inline_impl.cc" #include "element_class_triangle_3_inline_impl.cc" #include "element_class_triangle_6_inline_impl.cc" } // namespace akantu /* -------------------------------------------------------------------------- */ #if defined(AKANTU_STRUCTURAL_MECHANICS) #include "element_class_structural.hh" #endif #if defined(AKANTU_COHESIVE_ELEMENT) #include "cohesive_element.hh" #endif #if defined(AKANTU_IGFEM) #include "element_class_igfem.hh" #endif #endif /* __AKANTU_ELEMENT_CLASS_HH__ */ diff --git a/src/fe_engine/element_class_structural.hh b/src/fe_engine/element_class_structural.hh index 0af2d1891..d719c6e11 100644 --- a/src/fe_engine/element_class_structural.hh +++ b/src/fe_engine/element_class_structural.hh @@ -1,252 +1,254 @@ /** * @file element_class_structural.hh * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Specialization of the element classes for structural elements * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__ #define __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__ namespace akantu { /// Macro to generate the InterpolationProperty structures for different /// interpolation types #define AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY( \ itp_type, itp_geom_type, ndof, nb_stress, nb_dnds_cols) \ template <> struct InterpolationProperty<itp_type> { \ static const InterpolationKind kind{_itk_structural}; \ static const UInt nb_nodes_per_element{ \ InterpolationProperty<itp_geom_type>::nb_nodes_per_element}; \ static const InterpolationType itp_geometry_type{itp_geom_type}; \ static const UInt natural_space_dimension{ \ InterpolationProperty<itp_geom_type>::natural_space_dimension}; \ static const UInt nb_degree_of_freedom{ndof}; \ static const UInt nb_stress_components{nb_stress}; \ static const UInt dnds_columns{nb_dnds_cols}; \ } /* -------------------------------------------------------------------------- */ template <InterpolationType interpolation_type> class InterpolationElement<interpolation_type, _itk_structural> { public: using interpolation_property = InterpolationProperty<interpolation_type>; /// compute the shape values for a given set of points in natural coordinates static inline void computeShapes(const Matrix<Real> & natural_coord, const Matrix<Real> & real_coord, Tensor3<Real> & N) { for (UInt i = 0; i < natural_coord.cols(); ++i) { Matrix<Real> n_t = N(i); computeShapes(natural_coord(i), real_coord, n_t); } } /// compute the shape values for a given point in natural coordinates static inline void computeShapes(const Vector<Real> & natural_coord, const Matrix<Real> & real_coord, Matrix<Real> & N); /// compute shape derivatives (input is dxds) for a set of points static inline void computeShapeDerivatives(const Tensor3<Real> & Js, const Tensor3<Real> & DNDSs, const Matrix<Real> & R, Tensor3<Real> & Bs) { for (UInt i = 0; i < Js.size(2); ++i) { Matrix<Real> J = Js(i); Matrix<Real> DNDS = DNDSs(i); Matrix<Real> DNDX(DNDS.rows(), DNDS.cols()); auto inv_J = J.inverse(); DNDX.mul<false, false>(inv_J, DNDS); Matrix<Real> B_R = Bs(i); Matrix<Real> B(B_R.rows(), B_R.cols()); arrangeInVoigt(DNDX, B); B_R.mul<false, false>(B, R); } } /** * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of * shape functions along with variation of natural coordinates on a given set * of points in natural coordinates */ static inline void computeDNDS(const Matrix<Real> & natural_coord, const Matrix<Real> & real_coord, Tensor3<Real> & dnds) { for (UInt i = 0; i < natural_coord.cols(); ++i) { Matrix<Real> dnds_t = dnds(i); computeDNDS(natural_coord(i), real_coord, dnds_t); } } /** * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of * shape functions along with * variation of natural coordinates on a given point in natural * coordinates */ static inline void computeDNDS(const Vector<Real> & natural_coord, const Matrix<Real> & real_coord, Matrix<Real> & dnds); /** * arrange B in Voigt notation from DNDS */ static inline void arrangeInVoigt(const Matrix<Real> & dnds, Matrix<Real> & B) { // Default implementation assumes dnds is already in Voigt notation B.deepCopy(dnds); } public: static inline constexpr auto getNbNodesPerInterpolationElement() { return interpolation_property::nb_nodes_per_element; } static inline constexpr auto getShapeSize() { return interpolation_property::nb_nodes_per_element * interpolation_property::nb_degree_of_freedom * interpolation_property::nb_degree_of_freedom; } static inline constexpr auto getShapeDerivativesSize() { return interpolation_property::nb_nodes_per_element * interpolation_property::nb_degree_of_freedom * interpolation_property::nb_stress_components; } static inline constexpr auto getNaturalSpaceDimension() { return interpolation_property::natural_space_dimension; } static inline constexpr auto getNbDegreeOfFreedom() { return interpolation_property::nb_degree_of_freedom; } static inline constexpr auto getNbStressComponents() { return interpolation_property::nb_stress_components; } }; /// Macro to generate the element class structures for different structural /// element types /* -------------------------------------------------------------------------- */ #define AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY( \ elem_type, geom_type, interp_type, parent_el_type, elem_kind, sp, \ gauss_int_type, min_int_order) \ template <> struct ElementClassProperty<elem_type> { \ static const GeometricalType geometrical_type{geom_type}; \ static const InterpolationType interpolation_type{interp_type}; \ static const ElementType parent_element_type{parent_el_type}; \ static const ElementKind element_kind{elem_kind}; \ static const UInt spatial_dimension{sp}; \ static const GaussIntegrationType gauss_integration_type{gauss_int_type}; \ static const UInt polynomial_degree{min_int_order}; \ } /* -------------------------------------------------------------------------- */ /* ElementClass for structural elements */ /* -------------------------------------------------------------------------- */ template <ElementType element_type> class ElementClass<element_type, _ek_structural> : public GeometricalElement< ElementClassProperty<element_type>::geometrical_type>, public InterpolationElement< ElementClassProperty<element_type>::interpolation_type> { protected: using geometrical_element = GeometricalElement<ElementClassProperty<element_type>::geometrical_type>; using interpolation_element = InterpolationElement< ElementClassProperty<element_type>::interpolation_type>; using parent_element = ElementClass<ElementClassProperty<element_type>::parent_element_type>; public: static inline void computeRotationMatrix(Matrix<Real> & /*R*/, const Matrix<Real> & /*X*/, const Vector<Real> & /*extra_normal*/) { AKANTU_TO_IMPLEMENT(); } /// compute jacobian (or integration variable change factor) for a given point static inline void computeJMat(const Vector<Real> & natural_coords, const Matrix<Real> & Xs, Matrix<Real> & J) { Matrix<Real> dnds(Xs.rows(), Xs.cols()); parent_element::computeDNDS(natural_coords, dnds); J.mul<false, true>(dnds, Xs); } static inline void computeJMat(const Matrix<Real> & natural_coords, const Matrix<Real> & Xs, Tensor3<Real> & Js) { for (UInt i = 0; i < natural_coords.cols(); ++i) { // because non-const l-value reference does not bind to r-value Matrix<Real> J = Js(i); computeJMat(Vector<Real>(natural_coords(i)), Xs, J); } } static inline void computeJacobian(const Matrix<Real> & natural_coords, const Matrix<Real> & node_coords, Vector<Real> & jacobians) { using itp = typename interpolation_element::interpolation_property; Tensor3<Real> Js(itp::natural_space_dimension, itp::natural_space_dimension, natural_coords.cols()); computeJMat(natural_coords, node_coords, Js); for (UInt i = 0; i < natural_coords.cols(); ++i) { Matrix<Real> J = Js(i); jacobians(i) = J.det(); } } static inline void computeRotation(const Matrix<Real> & node_coords, Matrix<Real> & rotation); public: static AKANTU_GET_MACRO_NOT_CONST(Kind, _ek_structural, ElementKind); static AKANTU_GET_MACRO_NOT_CONST(P1ElementType, _not_defined, ElementType); static AKANTU_GET_MACRO_NOT_CONST(FacetType, _not_defined, ElementType); static constexpr auto getFacetType(__attribute__((unused)) UInt t = 0) { return _not_defined; } static constexpr AKANTU_GET_MACRO_NOT_CONST( SpatialDimension, ElementClassProperty<element_type>::spatial_dimension, UInt); static constexpr auto getFacetTypes() { return ElementClass<_not_defined>::getFacetTypes(); } }; } // namespace akantu /* -------------------------------------------------------------------------- */ #include "element_classes/element_class_hermite_inline_impl.cc" /* keep order */ #include "element_classes/element_class_bernoulli_beam_inline_impl.cc" #include "element_classes/element_class_kirchhoff_shell_inline_impl.cc" /* -------------------------------------------------------------------------- */ #endif /* __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__ */ diff --git a/src/fe_engine/element_class_tmpl.hh b/src/fe_engine/element_class_tmpl.hh index b58d164f1..4b8701579 100644 --- a/src/fe_engine/element_class_tmpl.hh +++ b/src/fe_engine/element_class_tmpl.hh @@ -1,531 +1,531 @@ /** * @file element_class_tmpl.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Thomas Menouillard <tmenouillard@stucky.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Wed Nov 29 2017 * * @brief Implementation of the inline templated function of the element class * descriptions * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" #include "gauss_integration_tmpl.hh" /* -------------------------------------------------------------------------- */ #include <type_traits> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_TMPL_HH__ #define __AKANTU_ELEMENT_CLASS_TMPL_HH__ namespace akantu { template <ElementType element_type, ElementKind element_kind> inline constexpr auto ElementClass<element_type, element_kind>::getFacetTypes() { return VectorProxy<const ElementType>( element_class_extra_geom_property::facet_type.data(), geometrical_element::getNbFacetTypes()); } /* -------------------------------------------------------------------------- */ /* GeometricalElement */ /* -------------------------------------------------------------------------- */ template <GeometricalType geometrical_type, GeometricalShapeType shape> inline constexpr auto GeometricalElement<geometrical_type, shape>::getFacetLocalConnectivityPerElement(UInt t) { int pos = 0; for (UInt i = 0; i < t; ++i) { pos += geometrical_property::nb_facets[i] * geometrical_property::nb_nodes_per_facet[i]; } return MatrixProxy<const UInt>( geometrical_property::facet_connectivity_vect.data() + pos, geometrical_property::nb_facets[t], geometrical_property::nb_nodes_per_facet[t]); } /* -------------------------------------------------------------------------- */ template <GeometricalType geometrical_type, GeometricalShapeType shape> inline UInt GeometricalElement<geometrical_type, shape>::getNbFacetsPerElement() { UInt total_nb_facets = 0; for (UInt n = 0; n < geometrical_property::nb_facet_types; ++n) { total_nb_facets += geometrical_property::nb_facets[n]; } return total_nb_facets; } /* -------------------------------------------------------------------------- */ template <GeometricalType geometrical_type, GeometricalShapeType shape> inline UInt GeometricalElement<geometrical_type, shape>::getNbFacetsPerElement(UInt t) { return geometrical_property::nb_facets[t]; } /* -------------------------------------------------------------------------- */ template <GeometricalType geometrical_type, GeometricalShapeType shape> template <class vector_type> inline bool GeometricalElement<geometrical_type, shape>::contains( const vector_type & coords) { return GeometricalShapeContains<shape>::contains(coords); } /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline bool GeometricalShapeContains<_gst_point>::contains(const vector_type & coords) { return (coords(0) < std::numeric_limits<Real>::epsilon()); } /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline bool GeometricalShapeContains<_gst_square>::contains(const vector_type & coords) { bool in = true; for (UInt i = 0; i < coords.size() && in; ++i) in &= ((coords(i) >= -(1. + std::numeric_limits<Real>::epsilon())) && (coords(i) <= (1. + std::numeric_limits<Real>::epsilon()))); return in; } /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline bool GeometricalShapeContains<_gst_triangle>::contains(const vector_type & coords) { bool in = true; Real sum = 0; for (UInt i = 0; (i < coords.size()) && in; ++i) { in &= ((coords(i) >= -(Math::getTolerance())) && (coords(i) <= (1. + Math::getTolerance()))); sum += coords(i); } if (in) return (in && (sum <= (1. + Math::getTolerance()))); return in; } /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline bool GeometricalShapeContains<_gst_prism>::contains(const vector_type & coords) { bool in = ((coords(0) >= -1.) && (coords(0) <= 1.)); // x in segment [-1, 1] // y and z in triangle in &= ((coords(1) >= 0) && (coords(1) <= 1.)); in &= ((coords(2) >= 0) && (coords(2) <= 1.)); Real sum = coords(1) + coords(2); return (in && (sum <= 1)); } /* -------------------------------------------------------------------------- */ /* InterpolationElement */ /* -------------------------------------------------------------------------- */ template <InterpolationType interpolation_type, InterpolationKind kind> inline void InterpolationElement<interpolation_type, kind>::computeShapes( const Matrix<Real> & natural_coord, Matrix<Real> & N) { UInt nb_points = natural_coord.cols(); for (UInt p = 0; p < nb_points; ++p) { Vector<Real> Np(N(p)); Vector<Real> ncoord_p(natural_coord(p)); computeShapes(ncoord_p, Np); } } /* -------------------------------------------------------------------------- */ template <InterpolationType interpolation_type, InterpolationKind kind> inline void InterpolationElement<interpolation_type, kind>::computeDNDS( const Matrix<Real> & natural_coord, Tensor3<Real> & dnds) { UInt nb_points = natural_coord.cols(); for (UInt p = 0; p < nb_points; ++p) { Matrix<Real> dnds_p(dnds(p)); Vector<Real> ncoord_p(natural_coord(p)); computeDNDS(ncoord_p, dnds_p); } } /* -------------------------------------------------------------------------- */ /** * interpolate on a point a field for which values are given on the * node of the element using the shape functions at this interpolation point * * @param nodal_values values of the function per node @f$ f_{ij} = f_{n_i j} *@f$ so it should be a matrix of size nb_nodes_per_element @f$\times@f$ *nb_degree_of_freedom * @param shapes value of shape functions at the interpolation point * @param interpolated interpolated value of f @f$ f_j(\xi) = \sum_i f_{n_i j} *N_i @f$ */ template <InterpolationType interpolation_type, InterpolationKind kind> inline void InterpolationElement<interpolation_type, kind>::interpolate( const Matrix<Real> & nodal_values, const Vector<Real> & shapes, Vector<Real> & interpolated) { Matrix<Real> interpm(interpolated.storage(), nodal_values.rows(), 1); Matrix<Real> shapesm( shapes.storage(), InterpolationProperty<interpolation_type>::nb_nodes_per_element, 1); interpm.mul<false, false>(nodal_values, shapesm); } /* -------------------------------------------------------------------------- */ /** * interpolate on several points a field for which values are given on the * node of the element using the shape functions at the interpolation point * * @param nodal_values values of the function per node @f$ f_{ij} = f_{n_i j} *@f$ so it should be a matrix of size nb_nodes_per_element @f$\times@f$ *nb_degree_of_freedom * @param shapes value of shape functions at the interpolation point * @param interpolated interpolated values of f @f$ f_j(\xi) = \sum_i f_{n_i j} *N_i @f$ */ template <InterpolationType interpolation_type, InterpolationKind kind> inline void InterpolationElement<interpolation_type, kind>::interpolate( const Matrix<Real> & nodal_values, const Matrix<Real> & shapes, Matrix<Real> & interpolated) { UInt nb_points = shapes.cols(); for (UInt p = 0; p < nb_points; ++p) { Vector<Real> Np(shapes(p)); Vector<Real> interpolated_p(interpolated(p)); interpolate(nodal_values, Np, interpolated_p); } } /* -------------------------------------------------------------------------- */ /** * interpolate the field on a point given in natural coordinates the field which * values are given on the node of the element * * @param natural_coords natural coordinates of point where to interpolate \xi * @param nodal_values values of the function per node @f$ f_{ij} = f_{n_i j} *@f$ so it should be a matrix of size nb_nodes_per_element @f$\times@f$ *nb_degree_of_freedom * @param interpolated interpolated value of f @f$ f_j(\xi) = \sum_i f_{n_i j} *N_i @f$ */ template <InterpolationType interpolation_type, InterpolationKind kind> inline void InterpolationElement<interpolation_type, kind>::interpolateOnNaturalCoordinates( const Vector<Real> & natural_coords, const Matrix<Real> & nodal_values, Vector<Real> & interpolated) { Vector<Real> shapes( InterpolationProperty<interpolation_type>::nb_nodes_per_element); computeShapes(natural_coords, shapes); interpolate(nodal_values, shapes, interpolated); } /* -------------------------------------------------------------------------- */ /// @f$ gradient_{ij} = \frac{\partial f_j}{\partial s_i} = \sum_k /// \frac{\partial N_k}{\partial s_i}f_{j n_k} @f$ template <InterpolationType interpolation_type, InterpolationKind kind> inline void InterpolationElement<interpolation_type, kind>::gradientOnNaturalCoordinates( const Vector<Real> & natural_coords, const Matrix<Real> & f, Matrix<Real> & gradient) { Matrix<Real> dnds( InterpolationProperty<interpolation_type>::natural_space_dimension, InterpolationProperty<interpolation_type>::nb_nodes_per_element); computeDNDS(natural_coords, dnds); gradient.mul<false, true>(f, dnds); } /* -------------------------------------------------------------------------- */ /* ElementClass */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeJMat(const Tensor3<Real> & dnds, const Matrix<Real> & node_coords, Tensor3<Real> & J) { UInt nb_points = dnds.size(2); for (UInt p = 0; p < nb_points; ++p) { Matrix<Real> J_p(J(p)); Matrix<Real> dnds_p(dnds(p)); computeJMat(dnds_p, node_coords, J_p); } } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeJMat(const Matrix<Real> & dnds, const Matrix<Real> & node_coords, Matrix<Real> & J) { /// @f$ J = dxds = dnds * x @f$ J.mul<false, true>(dnds, node_coords); } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeJacobian(const Matrix<Real> & natural_coords, const Matrix<Real> & node_coords, Vector<Real> & jacobians) { UInt nb_points = natural_coords.cols(); Matrix<Real> dnds(interpolation_property::natural_space_dimension, interpolation_property::nb_nodes_per_element); Matrix<Real> J(natural_coords.rows(), node_coords.rows()); for (UInt p = 0; p < nb_points; ++p) { Vector<Real> ncoord_p(natural_coords(p)); interpolation_element::computeDNDS(ncoord_p, dnds); computeJMat(dnds, node_coords, J); computeJacobian(J, jacobians(p)); } } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeJacobian(const Tensor3<Real> & J, Vector<Real> & jacobians) { UInt nb_points = J.size(2); for (UInt p = 0; p < nb_points; ++p) { computeJacobian(J(p), jacobians(p)); } } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeJacobian(const Matrix<Real> & J, Real & jacobians) { if (J.rows() == J.cols()) { jacobians = Math::det<element_property::spatial_dimension>(J.storage()); } else { interpolation_element::computeSpecialJacobian(J, jacobians); } } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeShapeDerivatives(const Tensor3<Real> & J, const Tensor3<Real> & dnds, Tensor3<Real> & shape_deriv) { UInt nb_points = J.size(2); for (UInt p = 0; p < nb_points; ++p) { Matrix<Real> shape_deriv_p(shape_deriv(p)); computeShapeDerivatives(J(p), dnds(p), shape_deriv_p); } } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeShapeDerivatives(const Matrix<Real> & J, const Matrix<Real> & dnds, Matrix<Real> & shape_deriv) { Matrix<Real> inv_J(J.rows(), J.cols()); Math::inv<element_property::spatial_dimension>(J.storage(), inv_J.storage()); shape_deriv.mul<false, false>(inv_J, dnds); } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::computeNormalsOnNaturalCoordinates( const Matrix<Real> & coord, Matrix<Real> & f, Matrix<Real> & normals) { UInt dimension = normals.rows(); UInt nb_points = coord.cols(); AKANTU_DEBUG_ASSERT((dimension - 1) == interpolation_property::natural_space_dimension, "cannot extract a normal because of dimension mismatch " << dimension - 1 << " " << interpolation_property::natural_space_dimension); Matrix<Real> J(dimension, interpolation_property::natural_space_dimension); for (UInt p = 0; p < nb_points; ++p) { interpolation_element::gradientOnNaturalCoordinates(coord(p), f, J); if (dimension == 2) { Math::normal2(J.storage(), normals(p).storage()); } if (dimension == 3) { Math::normal3(J(0).storage(), J(1).storage(), normals(p).storage()); } } } /* ------------------------------------------------------------------------- */ /** * In the non linear cases we need to iterate to find the natural coordinates *@f$\xi@f$ * provided real coordinates @f$x@f$. * * We want to solve: @f$ x- \phi(\xi) = 0@f$ with @f$\phi(\xi) = \sum_I N_I(\xi) *x_I@f$ * the mapping function which uses the nodal coordinates @f$x_I@f$. * * To that end we use the Newton method and the following series: * * @f$ \frac{\partial \phi(x_k)}{\partial \xi} \left( \xi_{k+1} - \xi_k \right) *= x - \phi(x_k)@f$ * * When we consider elements embedded in a dimension higher than them (2D *triangle in a 3D space for example) * @f$ J = \frac{\partial \phi(\xi_k)}{\partial \xi}@f$ is of dimension *@f$dim_{space} \times dim_{elem}@f$ which * is not invertible in most cases. Rather we can solve the problem: * * @f$ J^T J \left( \xi_{k+1} - \xi_k \right) = J^T \left( x - \phi(\xi_k) *\right) @f$ * * So that * * @f$ d\xi = \xi_{k+1} - \xi_k = (J^T J)^{-1} J^T \left( x - \phi(\xi_k) *\right) @f$ * * So that if the series converges we have: * * @f$ 0 = J^T \left( \phi(\xi_\infty) - x \right) @f$ * * And we see that this is ill-posed only if @f$ J^T x = 0@f$ which means that *the vector provided * is normal to any tangent which means it is outside of the element itself. * * @param real_coords: the real coordinates the natural coordinates are sought *for * @param node_coords: the coordinates of the nodes forming the element * @param natural_coords: output->the sought natural coordinates * @param spatial_dimension: spatial dimension of the problem * **/ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::inverseMap( const Vector<Real> & real_coords, const Matrix<Real> & node_coords, Vector<Real> & natural_coords, Real tolerance) { UInt spatial_dimension = real_coords.size(); UInt dimension = natural_coords.size(); // matrix copy of the real_coords Matrix<Real> mreal_coords(real_coords.storage(), spatial_dimension, 1); // initial guess // Matrix<Real> natural_guess(natural_coords.storage(), dimension, 1); natural_coords.clear(); // real space coordinates provided by initial guess Matrix<Real> physical_guess(dimension, 1); // objective function f = real_coords - physical_guess Matrix<Real> f(dimension, 1); // dnds computed on the natural_guess // Matrix<Real> dnds(interpolation_element::nb_nodes_per_element, // spatial_dimension); // J Jacobian matrix computed on the natural_guess Matrix<Real> J(spatial_dimension, dimension); // G = J^t * J Matrix<Real> G(spatial_dimension, spatial_dimension); // Ginv = G^{-1} Matrix<Real> Ginv(spatial_dimension, spatial_dimension); // J = Ginv * J^t Matrix<Real> F(spatial_dimension, dimension); // dxi = \xi_{k+1} - \xi in the iterative process Matrix<Real> dxi(spatial_dimension, 1); /* --------------------------- */ /* init before iteration loop */ /* --------------------------- */ // do interpolation auto update_f = [&f, &physical_guess, &natural_coords, &node_coords, &mreal_coords, dimension]() { Vector<Real> physical_guess_v(physical_guess.storage(), dimension); interpolation_element::interpolateOnNaturalCoordinates( natural_coords, node_coords, physical_guess_v); // compute initial objective function value f = real_coords - physical_guess f = mreal_coords; f -= physical_guess; // compute initial error auto error = f.norm<L_2>(); return error; }; auto inverse_map_error = update_f(); /* --------------------------- */ /* iteration loop */ /* --------------------------- */ while (tolerance < inverse_map_error) { // compute J^t interpolation_element::gradientOnNaturalCoordinates(natural_coords, node_coords, J); // compute G G.mul<true, false>(J, J); // inverse G Ginv.inverse(G); // compute F F.mul<false, true>(Ginv, J); // compute increment dxi.mul<false, false>(F, f); // update our guess natural_coords += Vector<Real>(dxi(0)); inverse_map_error = update_f(); } // memcpy(natural_coords.storage(), natural_guess.storage(), sizeof(Real) * // natural_coords.size()); } /* -------------------------------------------------------------------------- */ template <ElementType type, ElementKind kind> inline void ElementClass<type, kind>::inverseMap( const Matrix<Real> & real_coords, const Matrix<Real> & node_coords, Matrix<Real> & natural_coords, Real tolerance) { UInt nb_points = real_coords.cols(); for (UInt p = 0; p < nb_points; ++p) { Vector<Real> X(real_coords(p)); Vector<Real> ncoord_p(natural_coords(p)); inverseMap(X, node_coords, ncoord_p, tolerance); } } } // namespace akantu #endif /* __AKANTU_ELEMENT_CLASS_TMPL_HH__ */ diff --git a/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc b/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc index 407cb0af0..417f631c6 100644 --- a/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc @@ -1,222 +1,223 @@ /** * @file element_class_bernoulli_beam_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jul 15 2011 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Feb 19 2018 * * @brief Specialization of the element_class class for the type - _bernoulli_beam_2 + * _bernoulli_beam_2 * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim --x-----q1----|----q2-----x---> x -1 0 1 @endverbatim * */ + /* -------------------------------------------------------------------------- */ #include "aka_static_if.hh" #include "element_class_structural.hh" //#include "aka_element_classes_info.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__ #define __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_bernoulli_beam_2, _itp_lagrange_segment_2, 3, 2, 6); AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_bernoulli_beam_3, _itp_lagrange_segment_2, 6, 4, 6); AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_bernoulli_beam_2, _gt_segment_2, _itp_bernoulli_beam_2, _segment_2, _ek_structural, 2, _git_segment, 3); AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_bernoulli_beam_3, _gt_segment_2, _itp_bernoulli_beam_3, _segment_2, _ek_structural, 3, _git_segment, 3); /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeShapes( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & N) { Vector<Real> L(2); InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeShapes( natural_coords, L); Matrix<Real> H(2, 4); InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes( natural_coords, real_coord, H); // clang-format off // u1 v1 t1 u2 v2 t2 N = {{L(0), 0 , 0 , L(1), 0 , 0 }, // u {0 , H(0, 0), H(0, 1), 0 , H(0, 2), H(0, 3)}, // v {0 , H(1, 0), H(1, 1), 0 , H(1, 2), H(1, 3)}}; // theta // clang-format on } template <> inline void InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::computeShapes( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & N) { Vector<Real> L(2); InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeShapes( natural_coords, L); Matrix<Real> H(2, 4); InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes( natural_coords, real_coord, H); // clang-format off // u1 v1 w1 x1 y1 z1 u2 v2 w2 x2 y2 z2 N = {{L(0), 0 , 0 , 0 , 0 , 0 , L(1), 0 , 0 , 0 , 0 , 0 }, // u {0 , H(0, 0), 0 , 0 , H(0, 1), 0 , 0 , H(0, 2), 0 , 0 , H(0, 3), 0 }, // v {0 , 0 , H(0, 0), 0 , 0 , H(0, 1), 0 , 0 , H(0, 2), 0 , 0 , H(0, 3)}, // w {0 , 0 , 0 , L(0), 0 , 0 , 0 , 0 , 0 , L(1), 0 , 0 }, // thetax {0 , H(1, 0), 0 , 0 , H(1, 1), 0 , 0 , H(1, 2), 0 , 0 , H(1, 3), 0 }, // thetay {0 , 0 , H(1, 0), 0 , 0 , H(1, 1), 0 , 0 , H(1, 2), 0 , 0 , H(1, 3)}}; // thetaz // clang-format on } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeDNDS( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & dnds) { Matrix<Real> L(1, 2); InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeDNDS( natural_coords, L); Matrix<Real> H(1, 4); InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS( natural_coords, real_coord, H); // Storing the derivatives in dnds dnds.block(L, 0, 0); dnds.block(H, 0, 2); } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::arrangeInVoigt( const Matrix<Real> & dnds, Matrix<Real> & B) { auto L = dnds.block(0, 0, 1, 2); // Lagrange shape derivatives auto H = dnds.block(0, 2, 1, 4); // Hermite shape derivatives // clang-format off // u1 v1 t1 u2 v2 t2 B = {{L(0, 0), 0, 0, L(0, 1), 0, 0 }, {0, H(0, 0), H(0, 1), 0, H(0, 2), H(0, 3)}}; // clang-format on } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::computeDNDS( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & dnds) { InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeDNDS( natural_coords, real_coord, dnds); } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::arrangeInVoigt( const Matrix<Real> & dnds, Matrix<Real> & B) { auto L = dnds.block(0, 0, 1, 2); // Lagrange shape derivatives auto H = dnds.block(0, 2, 1, 4); // Hermite shape derivatives // clang-format off // u1 v1 w1 x1 y1 z1 u2 v2 w2 x2 y2 z2 B = {{L(0, 0), 0 , 0 , 0 , 0 , 0 , L(0, 1), 0 , 0 , 0 , 0 , 0 }, // eps {0 , H(0, 0), 0 , 0 , 0 , H(0, 1), 0 , H(0, 2), 0 , 0 , 0 , H(0, 3)}, // chi strong axis {0 , 0 ,-H(0, 0), 0 , H(0, 1), 0 , 0 , 0 ,-H(0, 2), 0 , H(0, 3), 0 }, // chi weak axis {0 , 0 , 0 , L(0, 0), 0 , 0 , 0 , 0 , 0 , L(0, 1), 0 , 0 }}; // chi torsion // clang-format on } /* -------------------------------------------------------------------------- */ template <> inline void ElementClass<_bernoulli_beam_2>::computeRotationMatrix( Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> &) { Vector<Real> x2 = X(1); // X2 Vector<Real> x1 = X(0); // X1 auto cs = (x2 - x1); cs.normalize(); auto c = cs(0); auto s = cs(1); // clang-format off /// Definition of the rotation matrix R = {{ c, s, 0.}, {-s, c, 0.}, { 0., 0., 1.}}; // clang-format on } /* -------------------------------------------------------------------------- */ template <> inline void ElementClass<_bernoulli_beam_3>::computeRotationMatrix( Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> & n) { Vector<Real> x2 = X(1); // X2 Vector<Real> x1 = X(0); // X1 auto dim = X.rows(); auto x = (x2 - x1); x.normalize(); auto x_n = x.crossProduct(n); Matrix<Real> Pe = {{1., 0., 0.}, {0., -1., 0.}, {0., 0., 1.}}; Matrix<Real> Pg(dim, dim); Pg(0) = x; Pg(1) = x_n; Pg(2) = n; Pe *= Pg.inverse(); R.clear(); /// Definition of the rotation matrix for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) R(i + dim, j + dim) = R(i, j) = Pe(i, j); } } // namespace akantu #endif /* __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc b/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc index 03972b2a0..33ac526aa 100644 --- a/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc @@ -1,179 +1,179 @@ /** * @file element_class_hermite_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> - * @author Lucas Frérot <lucas.frerot@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * - * @date creation: Fri Jul 15 2011 - * @date last modification: Sun Oct 19 2014 + * @date creation: Fri Nov 10 2017 + * @date last modification: Mon Feb 19 2018 * * @brief Specialization of the element_class class for the type - _hermite + * _hermite * * @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) + * Copyright (©) 2016-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim --x-----q1----|----q2-----x---> x -1 0 1 @endverbatim * * @subsection shapes Shape functions * @f[ * \begin{array}{ll} * M_1(\xi) &= 1/4(\xi^{3}/-3\xi+2)\\ * M_2(\xi) &= -1/4(\xi^{3}-3\xi-2) * \end{array} * * \begin{array}{ll} * L_1(\xi) &= 1/4(\xi^{3}-\xi^{2}-\xi+1)\\ * L_2(\xi) &= 1/4(\xi^{3}+\xi^{2}-\xi-1) * \end{array} * * \begin{array}{ll} * M'_1(\xi) &= 3/4(\xi^{2}-1)\\ * M'_2(\xi) &= -3/4(\xi^{2}-1) * \end{array} * * \begin{array}{ll} * L'_1(\xi) &= 1/4(3\xi^{2}-2\xi-1)\\ * L'_2(\xi) &= 1/4(3\xi^{2}+2\xi-1) * \end{array} *@f] * * @subsection dnds Shape derivatives * *@f[ * \begin{array}{ll} * N'_1(\xi) &= -1/2\\ * N'_2(\xi) &= 1/2 * \end{array}] * * \begin{array}{ll} * -M''_1(\xi) &= -3\xi/2\\ * -M''_2(\xi) &= 3\xi/2\\ * \end{array} * * \begin{array}{ll} * -L''_1(\xi) &= -1/2a(3\xi/a-1)\\ * -L''_2(\xi) &= -1/2a(3\xi/a+1) * \end{array} *@f] * */ + /* -------------------------------------------------------------------------- */ #include "aka_static_if.hh" #include "element_class_structural.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__ #define __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_hermite_2, _itp_lagrange_segment_2, 2, 1, 4); /* -------------------------------------------------------------------------- */ namespace { namespace details { inline Real computeLength(const Matrix<Real> & real_coord) { Vector<Real> x1 = real_coord(0); Vector<Real> x2 = real_coord(1); return x1.distance(x2); } inline void computeShapes(const Vector<Real> & natural_coords, Real a, Matrix<Real> & N) { /// natural coordinate Real xi = natural_coords(0); // Cubic Hermite splines interpolating displacement auto M1 = 1. / 4. * Math::pow<2>(xi - 1) * (xi + 2); auto M2 = 1. / 4. * Math::pow<2>(xi + 1) * (2 - xi); auto L1 = a / 4. * Math::pow<2>(xi - 1) * (xi + 1); auto L2 = a / 4. * Math::pow<2>(xi + 1) * (xi - 1); #if 1 // Version where we also interpolate the rotations // Derivatives (with respect to x) of previous functions interpolating // rotations auto M1_ = 3. / (4. * a) * (xi * xi - 1); auto M2_ = 3. / (4. * a) * (1 - xi * xi); auto L1_ = 1 / 4. * (3 * xi * xi - 2 * xi - 1); auto L2_ = 1 / 4. * (3 * xi * xi + 2 * xi - 1); // clang-format off // v1 t1 v2 t2 N = {{M1 , L1 , M2 , L2}, // displacement interpolation {M1_, L1_, M2_, L2_}}; // rotation interpolation // clang-format on #else // Version where we only interpolate displacements // clang-format off // v1 t1 v2 t2 N = {{M1, L1, M2, L2}}; // clang-format on #endif } /* ---------------------------------------------------------------------- */ inline void computeDNDS(const Vector<Real> & natural_coords, Real a, Matrix<Real> & B) { // natural coordinate Real xi = natural_coords(0); // Derivatives with respect to xi for rotations auto M1__ = 3. / 2. * xi; auto M2__ = 3. / 2. * (-xi); auto L1__ = a / 2. * (3 * xi - 1); auto L2__ = a / 2. * (3 * xi + 1); // v1 t1 v2 t2 B = {{M1__, L1__, M2__, L2__}}; // computing curvature : {chi} = [B]{d} B /= a; // to account for first order deriv w/r to x } } // namespace details } // namespace /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & N) { auto L = details::computeLength(real_coord); details::computeShapes(natural_coords, L / 2, N); } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & B) { auto L = details::computeLength(real_coord); details::computeDNDS(natural_coords, L / 2, B); } } // namespace akantu #endif /* __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.cc b/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.cc index da0c877fc..0906a90be 100644 --- a/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.cc @@ -1,259 +1,259 @@ /** * @file element_class_hexahedron_20_inline_impl.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Sacha Laffely <sacha.laffely@epfl.ch> * @author Damien Scantamburlo <damien.scantamburlo@epfl.ch> * * @date creation: Tue Mar 31 2015 - * @date last modification: Thu Jul 16 2015 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _hexahedron_20 * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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. +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. +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 <http://www.gnu.org/licenses/>. +along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \y \z / | / 7-----|18--------6 /| | / /| / | | / / | 19 | | / 17 | / 15 | / / 14 / | | / / | 4-------16---/---5 | | | +----|------------\x | 3-------10-|-----2 | / | / 12 / 13 / | 11 | 9 | / | / |/ |/ 0--------8-------1 x y z * N0 -1 -1 -1 * N1 1 -1 -1 * N2 1 1 -1 * N3 -1 1 -1 * N4 -1 -1 1 * N5 1 -1 1 * N6 1 1 1 * N7 -1 1 1 * N8 0 -1 -1 * N9 1 0 -1 * N10 0 1 -1 * N11 -1 0 -1 * N12 -1 -1 0 * N13 1 -1 0 * N14 1 1 0 * N15 -1 1 0 * N16 0 -1 1 * N17 1 0 1 * N18 0 1 1 * N19 -1 0 1 */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_hexahedron_20, _gt_hexahedron_20, _itp_serendip_hexahedron_20, _ek_regular, 3, _git_segment, 3); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_serendip_hexahedron_20>::computeShapes( const vector_type & c, vector_type & N) { // Shape function , Natural coordinates N(0) = 0.125 * (1 - c(0)) * (1 - c(1)) * (1 - c(2)) * (-2 - c(0) - c(1) - c(2)); N(1) = 0.125 * (1 + c(0)) * (1 - c(1)) * (1 - c(2)) * (-2 + c(0) - c(1) - c(2)); N(2) = 0.125 * (1 + c(0)) * (1 + c(1)) * (1 - c(2)) * (-2 + c(0) + c(1) - c(2)); N(3) = 0.125 * (1 - c(0)) * (1 + c(1)) * (1 - c(2)) * (-2 - c(0) + c(1) - c(2)); N(4) = 0.125 * (1 - c(0)) * (1 - c(1)) * (1 + c(2)) * (-2 - c(0) - c(1) + c(2)); N(5) = 0.125 * (1 + c(0)) * (1 - c(1)) * (1 + c(2)) * (-2 + c(0) - c(1) + c(2)); N(6) = 0.125 * (1 + c(0)) * (1 + c(1)) * (1 + c(2)) * (-2 + c(0) + c(1) + c(2)); N(7) = 0.125 * (1 - c(0)) * (1 + c(1)) * (1 + c(2)) * (-2 - c(0) + c(1) + c(2)); N(8) = 0.25 * (1 - c(0) * c(0)) * (1 - c(1)) * (1 - c(2)); N(9) = 0.25 * (1 - c(1) * c(1)) * (1 + c(0)) * (1 - c(2)); N(10) = 0.25 * (1 - c(0) * c(0)) * (1 + c(1)) * (1 - c(2)); N(11) = 0.25 * (1 - c(1) * c(1)) * (1 - c(0)) * (1 - c(2)); N(12) = 0.25 * (1 - c(2) * c(2)) * (1 - c(0)) * (1 - c(1)); N(13) = 0.25 * (1 - c(2) * c(2)) * (1 + c(0)) * (1 - c(1)); N(14) = 0.25 * (1 - c(2) * c(2)) * (1 + c(0)) * (1 + c(1)); N(15) = 0.25 * (1 - c(2) * c(2)) * (1 - c(0)) * (1 + c(1)); N(16) = 0.25 * (1 - c(0) * c(0)) * (1 - c(1)) * (1 + c(2)); N(17) = 0.25 * (1 - c(1) * c(1)) * (1 + c(0)) * (1 + c(2)); N(18) = 0.25 * (1 - c(0) * c(0)) * (1 + c(1)) * (1 + c(2)); N(19) = 0.25 * (1 - c(1) * c(1)) * (1 - c(0)) * (1 + c(2)); } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_serendip_hexahedron_20>::computeDNDS( const vector_type & c, matrix_type & dnds) { // derivatives // ddx dnds(0, 0) = 0.25 * (c(0) + 0.5 * (c(1) + c(2) + 1)) * (c(1) - 1) * (c(2) - 1); dnds(0, 1) = 0.25 * (c(0) - 0.5 * (c(1) + c(2) + 1)) * (c(1) - 1) * (c(2) - 1); dnds(0, 2) = -0.25 * (c(0) + 0.5 * (c(1) - c(2) - 1)) * (c(1) + 1) * (c(2) - 1); dnds(0, 3) = -0.25 * (c(0) - 0.5 * (c(1) - c(2) - 1)) * (c(1) + 1) * (c(2) - 1); dnds(0, 4) = -0.25 * (c(0) + 0.5 * (c(1) - c(2) + 1)) * (c(1) - 1) * (c(2) + 1); dnds(0, 5) = -0.25 * (c(0) - 0.5 * (c(1) - c(2) + 1)) * (c(1) - 1) * (c(2) + 1); dnds(0, 6) = 0.25 * (c(0) + 0.5 * (c(1) + c(2) - 1)) * (c(1) + 1) * (c(2) + 1); dnds(0, 7) = 0.25 * (c(0) - 0.5 * (c(1) + c(2) - 1)) * (c(1) + 1) * (c(2) + 1); dnds(0, 8) = -0.5 * c(0) * (c(1) - 1) * (c(2) - 1); dnds(0, 9) = 0.25 * (c(1) * c(1) - 1) * (c(2) - 1); dnds(0, 10) = 0.5 * c(0) * (c(1) + 1) * (c(2) - 1); dnds(0, 11) = -0.25 * (c(1) * c(1) - 1) * (c(2) - 1); dnds(0, 12) = -0.25 * (c(2) * c(2) - 1) * (c(1) - 1); dnds(0, 13) = 0.25 * (c(1) - 1) * (c(2) * c(2) - 1); dnds(0, 14) = -0.25 * (c(1) + 1) * (c(2) * c(2) - 1); dnds(0, 15) = 0.25 * (c(1) + 1) * (c(2) * c(2) - 1); dnds(0, 16) = 0.5 * c(0) * (c(1) - 1) * (c(2) + 1); dnds(0, 17) = -0.25 * (c(2) + 1) * (c(1) * c(1) - 1); dnds(0, 18) = -0.5 * c(0) * (c(1) + 1) * (c(2) + 1); dnds(0, 19) = 0.25 * (c(2) + 1) * (c(1) * c(1) - 1); // ddy dnds(1, 0) = 0.25 * (c(1) + 0.5 * (c(0) + c(2) + 1)) * (c(0) - 1) * (c(2) - 1); dnds(1, 1) = -0.25 * (c(1) - 0.5 * (c(0) - c(2) - 1)) * (c(0) + 1) * (c(2) - 1); dnds(1, 2) = -0.25 * (c(1) + 0.5 * (c(0) - c(2) - 1)) * (c(0) + 1) * (c(2) - 1); dnds(1, 3) = 0.25 * (c(1) - 0.5 * (c(0) + c(2) + 1)) * (c(0) - 1) * (c(2) - 1); dnds(1, 4) = -0.25 * (c(1) + 0.5 * (c(0) - c(2) + 1)) * (c(0) - 1) * (c(2) + 1); dnds(1, 5) = 0.25 * (c(1) - 0.5 * (c(0) + c(2) - 1)) * (c(0) + 1) * (c(2) + 1); dnds(1, 6) = 0.25 * (c(1) + 0.5 * (c(0) + c(2) - 1)) * (c(0) + 1) * (c(2) + 1); dnds(1, 7) = -0.25 * (c(1) - 0.5 * (c(0) - c(2) + 1)) * (c(0) - 1) * (c(2) + 1); dnds(1, 8) = -0.25 * (c(0) * c(0) - 1) * (c(2) - 1); dnds(1, 9) = 0.5 * c(1) * (c(0) + 1) * (c(2) - 1); dnds(1, 10) = 0.25 * (c(0) * c(0) - 1) * (c(2) - 1); dnds(1, 11) = -0.5 * c(1) * (c(0) - 1) * (c(2) - 1); dnds(1, 12) = -0.25 * (c(2) * c(2) - 1) * (c(0) - 1); dnds(1, 13) = 0.25 * (c(0) + 1) * (c(2) * c(2) - 1); dnds(1, 14) = -0.25 * (c(0) + 1) * (c(2) * c(2) - 1); dnds(1, 15) = 0.25 * (c(0) - 1) * (c(2) * c(2) - 1); dnds(1, 16) = 0.25 * (c(2) + 1) * (c(0) * c(0) - 1); dnds(1, 17) = -0.5 * c(1) * (c(0) + 1) * (c(2) + 1); dnds(1, 18) = -0.25 * (c(2) + 1) * (c(0) * c(0) - 1); dnds(1, 19) = 0.5 * c(1) * (c(0) - 1) * (c(2) + 1); // ddz dnds(2, 0) = 0.25 * (c(2) + 0.5 * (c(0) + c(1) + 1)) * (c(0) - 1) * (c(1) - 1); dnds(2, 1) = -0.25 * (c(2) - 0.5 * (c(0) - c(1) - 1)) * (c(0) + 1) * (c(1) - 1); dnds(2, 2) = 0.25 * (c(2) - 0.5 * (c(0) + c(1) - 1)) * (c(0) + 1) * (c(1) + 1); dnds(2, 3) = -0.25 * (c(2) + 0.5 * (c(0) - c(1) + 1)) * (c(0) - 1) * (c(1) + 1); dnds(2, 4) = 0.25 * (c(2) - 0.5 * (c(0) + c(1) + 1)) * (c(0) - 1) * (c(1) - 1); dnds(2, 5) = -0.25 * (c(2) + 0.5 * (c(0) - c(1) - 1)) * (c(0) + 1) * (c(1) - 1); dnds(2, 6) = 0.25 * (c(2) + 0.5 * (c(0) + c(1) - 1)) * (c(0) + 1) * (c(1) + 1); dnds(2, 7) = -0.25 * (c(2) - 0.5 * (c(0) - c(1) + 1)) * (c(0) - 1) * (c(1) + 1); dnds(2, 8) = -0.25 * (c(0) * c(0) - 1) * (c(1) - 1); dnds(2, 9) = 0.25 * (c(1) * c(1) - 1) * (c(0) + 1); dnds(2, 10) = 0.25 * (c(0) * c(0) - 1) * (c(1) + 1); dnds(2, 11) = -0.25 * (c(1) * c(1) - 1) * (c(0) - 1); dnds(2, 12) = -0.5 * c(2) * (c(1) - 1) * (c(0) - 1); dnds(2, 13) = 0.5 * c(2) * (c(0) + 1) * (c(1) - 1); dnds(2, 14) = -0.5 * c(2) * (c(0) + 1) * (c(1) + 1); dnds(2, 15) = 0.5 * c(2) * (c(0) - 1) * (c(1) + 1); dnds(2, 16) = 0.25 * (c(1) - 1) * (c(0) * c(0) - 1); dnds(2, 17) = -0.25 * (c(0) + 1) * (c(1) * c(1) - 1); dnds(2, 18) = -0.25 * (c(1) + 1) * (c(0) * c(0) - 1); dnds(2, 19) = 0.25 * (c(0) - 1) * (c(1) * c(1) - 1); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_hexahedron_20>::getInradius(const Matrix<Real> & coord) { Vector<Real> u0 = coord(0); Vector<Real> u1 = coord(1); Vector<Real> u2 = coord(2); Vector<Real> u3 = coord(3); Vector<Real> u4 = coord(4); Vector<Real> u5 = coord(5); Vector<Real> u6 = coord(6); Vector<Real> u7 = coord(7); Vector<Real> u8 = coord(8); Vector<Real> u9 = coord(9); Vector<Real> u10 = coord(10); Vector<Real> u11 = coord(11); Vector<Real> u12 = coord(12); Vector<Real> u13 = coord(13); Vector<Real> u14 = coord(14); Vector<Real> u15 = coord(15); Vector<Real> u16 = coord(16); Vector<Real> u17 = coord(17); Vector<Real> u18 = coord(18); Vector<Real> u19 = coord(19); Real a = u0.distance(u1); Real b = u1.distance(u2); Real c = u2.distance(u3); Real d = u3.distance(u0); Real e = u0.distance(u4); Real f = u1.distance(u5); Real g = u2.distance(u6); Real h = u3.distance(u7); Real i = u4.distance(u5); Real j = u5.distance(u6); Real k = u6.distance(u7); Real l = u7.distance(u4); Real x = std::min(a, std::min(b, std::min(c, d))); Real y = std::min(e, std::min(f, std::min(g, h))); Real z = std::min(i, std::min(j, std::min(k, l))); Real p = std::min(x, std::min(y, z)); return p; } diff --git a/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.cc b/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.cc index 9fb1cc1ac..7a96249a3 100644 --- a/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.cc @@ -1,254 +1,253 @@ /** * @file element_class_hexahedron_8_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Peter Spijker <peter.spijker@epfl.ch> * * @date creation: Mon Mar 14 2011 - * @date last modification: Sat Sep 12 2015 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _hexahedron_8 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \zeta ^ (-1,1,1) | (1,1,1) 7---|------6 /| | /| / | | / | (-1,-1,1) 4----------5 | (1,-1,1) | | | | | | | | | | | | +---|-------> \xi | | / | | (-1,1,-1) | 3-/-----|--2 (1,1,-1) | / / | / |/ / |/ 0-/--------1 (-1,-1,-1) / (1,-1,-1) / \eta @endverbatim * * @subsection shapes Shape functions * @f[ * \begin{array}{llll} * N1 = (1 - \xi) (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N1}{\partial \xi} = - (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N1}{\partial \eta} = - (1 - \xi) (1 - \zeta) / 8 * & \frac{\partial N1}{\partial \zeta} = - (1 - \xi) (1 - \eta) / 8 \\ * N2 = (1 + \xi) (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N2}{\partial \xi} = (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N2}{\partial \eta} = - (1 + \xi) (1 - \zeta) / 8 * & \frac{\partial N2}{\partial \zeta} = - (1 + \xi) (1 - \eta) / 8 \\ * N3 = (1 + \xi) (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N3}{\partial \xi} = (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N3}{\partial \eta} = (1 + \xi) (1 - \zeta) / 8 * & \frac{\partial N3}{\partial \zeta} = - (1 + \xi) (1 + \eta) / 8 \\ * N4 = (1 - \xi) (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N4}{\partial \xi} = - (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N4}{\partial \eta} = (1 - \xi) (1 - \zeta) / 8 * & \frac{\partial N4}{\partial \zeta} = - (1 - \xi) (1 + \eta) / 8 \\ * N5 = (1 - \xi) (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N5}{\partial \xi} = - (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N5}{\partial \eta} = - (1 - \xi) (1 + \zeta) / 8 * & \frac{\partial N5}{\partial \zeta} = (1 - \xi) (1 - \eta) / 8 \\ * N6 = (1 + \xi) (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N6}{\partial \xi} = (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N6}{\partial \eta} = - (1 + \xi) (1 + \zeta) / 8 * & \frac{\partial N6}{\partial \zeta} = (1 + \xi) (1 - \eta) / 8 \\ * N7 = (1 + \xi) (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N7}{\partial \xi} = (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N7}{\partial \eta} = (1 + \xi) (1 + \zeta) / 8 * & \frac{\partial N7}{\partial \zeta} = (1 + \xi) (1 + \eta) / 8 \\ * N8 = (1 - \xi) (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N8}{\partial \xi} = - (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N8}{\partial \eta} = (1 - \xi) (1 + \zeta) / 8 * & \frac{\partial N8}{\partial \zeta} = (1 - \xi) (1 + \eta) / 8 \\ * \end{array} * @f] * * @subsection quad_points Position of quadrature points * @f{eqnarray*}{ * \xi_{q0} &=& -1/\sqrt{3} \qquad \eta_{q0} = -1/\sqrt{3} \qquad \zeta_{q0} = -1/\sqrt{3} \\ * \xi_{q1} &=& 1/\sqrt{3} \qquad \eta_{q1} = -1/\sqrt{3} \qquad \zeta_{q1} = -1/\sqrt{3} \\ * \xi_{q2} &=& 1/\sqrt{3} \qquad \eta_{q2} = 1/\sqrt{3} \qquad \zeta_{q2} = -1/\sqrt{3} \\ * \xi_{q3} &=& -1/\sqrt{3} \qquad \eta_{q3} = 1/\sqrt{3} \qquad \zeta_{q3} = -1/\sqrt{3} \\ * \xi_{q4} &=& -1/\sqrt{3} \qquad \eta_{q4} = -1/\sqrt{3} \qquad \zeta_{q4} = 1/\sqrt{3} \\ * \xi_{q5} &=& 1/\sqrt{3} \qquad \eta_{q5} = -1/\sqrt{3} \qquad \zeta_{q5} = 1/\sqrt{3} \\ * \xi_{q6} &=& 1/\sqrt{3} \qquad \eta_{q6} = 1/\sqrt{3} \qquad \zeta_{q6} = 1/\sqrt{3} \\ * \xi_{q7} &=& -1/\sqrt{3} \qquad \eta_{q7} = 1/\sqrt{3} \qquad \zeta_{q7} = 1/\sqrt{3} \\ * @f} */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_hexahedron_8, _gt_hexahedron_8, _itp_lagrange_hexahedron_8, _ek_regular, 3, _git_segment, 2); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_hexahedron_8>::computeShapes( const vector_type & c, vector_type & N) { /// Natural coordinates N(0) = .125 * (1 - c(0)) * (1 - c(1)) * (1 - c(2)); /// N1(q_0) N(1) = .125 * (1 + c(0)) * (1 - c(1)) * (1 - c(2)); /// N2(q_0) N(2) = .125 * (1 + c(0)) * (1 + c(1)) * (1 - c(2)); /// N3(q_0) N(3) = .125 * (1 - c(0)) * (1 + c(1)) * (1 - c(2)); /// N4(q_0) N(4) = .125 * (1 - c(0)) * (1 - c(1)) * (1 + c(2)); /// N5(q_0) N(5) = .125 * (1 + c(0)) * (1 - c(1)) * (1 + c(2)); /// N6(q_0) N(6) = .125 * (1 + c(0)) * (1 + c(1)) * (1 + c(2)); /// N7(q_0) N(7) = .125 * (1 - c(0)) * (1 + c(1)) * (1 + c(2)); /// N8(q_0) } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_hexahedron_8>::computeDNDS( const vector_type & c, matrix_type & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial * N4}{\partial \xi} * & \frac{\partial N5}{\partial \xi} & \frac{\partial * N6}{\partial \xi} * & \frac{\partial N7}{\partial \xi} & \frac{\partial * N8}{\partial \xi}\\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial * N4}{\partial \eta} * & \frac{\partial N5}{\partial \eta} & \frac{\partial * N6}{\partial \eta} * & \frac{\partial N7}{\partial \eta} & \frac{\partial * N8}{\partial \eta}\\ * \frac{\partial N1}{\partial \zeta} & \frac{\partial N2}{\partial * \zeta} * & \frac{\partial N3}{\partial \zeta} & \frac{\partial * N4}{\partial \zeta} * & \frac{\partial N5}{\partial \zeta} & \frac{\partial * N6}{\partial \zeta} * & \frac{\partial N7}{\partial \zeta} & \frac{\partial * N8}{\partial \zeta} * \end{array} * \right) * @f] */ dnds(0, 0) = -.125 * (1 - c(1)) * (1 - c(2)); ; dnds(0, 1) = .125 * (1 - c(1)) * (1 - c(2)); ; dnds(0, 2) = .125 * (1 + c(1)) * (1 - c(2)); ; dnds(0, 3) = -.125 * (1 + c(1)) * (1 - c(2)); ; dnds(0, 4) = -.125 * (1 - c(1)) * (1 + c(2)); ; dnds(0, 5) = .125 * (1 - c(1)) * (1 + c(2)); ; dnds(0, 6) = .125 * (1 + c(1)) * (1 + c(2)); ; dnds(0, 7) = -.125 * (1 + c(1)) * (1 + c(2)); ; dnds(1, 0) = -.125 * (1 - c(0)) * (1 - c(2)); ; dnds(1, 1) = -.125 * (1 + c(0)) * (1 - c(2)); ; dnds(1, 2) = .125 * (1 + c(0)) * (1 - c(2)); ; dnds(1, 3) = .125 * (1 - c(0)) * (1 - c(2)); ; dnds(1, 4) = -.125 * (1 - c(0)) * (1 + c(2)); ; dnds(1, 5) = -.125 * (1 + c(0)) * (1 + c(2)); ; dnds(1, 6) = .125 * (1 + c(0)) * (1 + c(2)); ; dnds(1, 7) = .125 * (1 - c(0)) * (1 + c(2)); ; dnds(2, 0) = -.125 * (1 - c(0)) * (1 - c(1)); ; dnds(2, 1) = -.125 * (1 + c(0)) * (1 - c(1)); ; dnds(2, 2) = -.125 * (1 + c(0)) * (1 + c(1)); ; dnds(2, 3) = -.125 * (1 - c(0)) * (1 + c(1)); ; dnds(2, 4) = .125 * (1 - c(0)) * (1 - c(1)); ; dnds(2, 5) = .125 * (1 + c(0)) * (1 - c(1)); ; dnds(2, 6) = .125 * (1 + c(0)) * (1 + c(1)); ; dnds(2, 7) = .125 * (1 - c(0)) * (1 + c(1)); ; } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_hexahedron_8>::getInradius(const Matrix<Real> & coord) { Vector<Real> u0 = coord(0); Vector<Real> u1 = coord(1); Vector<Real> u2 = coord(2); Vector<Real> u3 = coord(3); Vector<Real> u4 = coord(4); Vector<Real> u5 = coord(5); Vector<Real> u6 = coord(6); Vector<Real> u7 = coord(7); Real a = u0.distance(u1); Real b = u1.distance(u2); Real c = u2.distance(u3); Real d = u3.distance(u0); Real e = u0.distance(u4); Real f = u1.distance(u5); Real g = u2.distance(u6); Real h = u3.distance(u7); Real i = u4.distance(u5); Real j = u5.distance(u6); Real k = u6.distance(u7); Real l = u7.distance(u4); Real x = std::min(a, std::min(b, std::min(c, d))); Real y = std::min(e, std::min(f, std::min(g, h))); Real z = std::min(i, std::min(j, std::min(k, l))); Real p = std::min(x, std::min(y, z)); return p; } diff --git a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc index b74beaa9e..1f75e71c8 100644 --- a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc @@ -1,212 +1,214 @@ /** * @file element_class_kirchhoff_shell_inline_impl.cc * + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 04 2014 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Feb 21 2018 * * @brief Element class Kirchhoff Shell * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "element_class_structural.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ #define __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY( _itp_discrete_kirchhoff_triangle_18, _itp_lagrange_triangle_3, 6, 6, 21); AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY( _discrete_kirchhoff_triangle_18, _gt_triangle_3, _itp_discrete_kirchhoff_triangle_18, _triangle_3, _ek_structural, 3, _git_triangle, 2); /* -------------------------------------------------------------------------- */ namespace detail { inline void computeBasisChangeMatrix(Matrix<Real> & P, const Matrix<Real> & X) { Vector<Real> X1 = X(0); Vector<Real> X2 = X(1); Vector<Real> X3 = X(2); Vector<Real> a1 = X2 - X1; Vector<Real> a2 = X3 - X1; a1.normalize(); Vector<Real> e3 = a1.crossProduct(a2); e3.normalize(); Vector<Real> e2 = e3.crossProduct(a1); P(0) = a1; P(1) = e2; P(2) = e3; P = P.transpose(); } } /* -------------------------------------------------------------------------- */ template <> inline void ElementClass<_discrete_kirchhoff_triangle_18>::computeRotationMatrix( Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> &) { auto dim = X.rows(); Matrix<Real> P(dim, dim); detail::computeBasisChangeMatrix(P, X); R.clear(); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) R(i + dim, j + dim) = R(i, j) = P(i, j); } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeShapes( const Vector<Real> & /*natural_coords*/, const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*N*/) {} /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeDNDS( const Vector<Real> & natural_coords, const Matrix<Real> & real_coordinates, Matrix<Real> & B) { auto dim = real_coordinates.cols(); Matrix<Real> P(dim, dim); detail::computeBasisChangeMatrix(P, real_coordinates); auto X = P * real_coordinates; Vector<Real> X1 = X(0); Vector<Real> X2 = X(1); Vector<Real> X3 = X(2); std::array<Vector<Real>, 3> A = {X2 - X1, X3 - X2, X1 - X3}; std::array<Real, 3> L, C, S; // Setting all last coordinates to 0 std::for_each(A.begin(), A.end(), [](auto & a) { a(2) = 0; }); // Computing lengths std::transform(A.begin(), A.end(), L.begin(), [](auto & a) { return a.template norm<L_2>(); }); // Computing cosines std::transform(A.begin(), A.end(), L.begin(), C.begin(), [](auto & a, auto & l) { return a(0) / l; }); // Computing sines std::transform(A.begin(), A.end(), L.begin(), S.begin(), [](auto & a, auto & l) { return a(1) / l; }); // Natural coordinates Real xi = natural_coords(0); Real eta = natural_coords(1); // Derivative of quadratic interpolation functions Matrix<Real> dP = {{4 * (1 - 2 * xi - eta), 4 * eta, -4 * eta}, {-4 * xi, 4 * xi, 4 * (1 - xi - 2 * eta)}}; Matrix<Real> dNx1 = { {3. / 2 * (dP(0, 0) * C[0] / L[0] - dP(0, 2) * C[2] / L[2]), 3. / 2 * (dP(0, 1) * C[1] / L[1] - dP(0, 0) * C[0] / L[0]), 3. / 2 * (dP(0, 2) * C[2] / L[2] - dP(0, 1) * C[1] / L[1])}, {3. / 2 * (dP(1, 0) * C[0] / L[0] - dP(1, 2) * C[2] / L[2]), 3. / 2 * (dP(1, 1) * C[1] / L[1] - dP(1, 0) * C[0] / L[0]), 3. / 2 * (dP(1, 2) * C[2] / L[2] - dP(1, 1) * C[1] / L[1])}}; Matrix<Real> dNx2 = { // clang-format off {-1 - 3. / 4 * (dP(0, 0) * C[0] * C[0] + dP(0, 2) * C[2] * C[2]), 1 - 3. / 4 * (dP(0, 1) * C[1] * C[1] + dP(0, 0) * C[0] * C[0]), - 3. / 4 * (dP(0, 2) * C[2] * C[2] + dP(0, 1) * C[1] * C[1])}, {-1 - 3. / 4 * (dP(1, 0) * C[0] * C[0] + dP(1, 2) * C[2] * C[2]), - 3. / 4 * (dP(1, 1) * C[1] * C[1] + dP(1, 0) * C[0] * C[0]), 1 - 3. / 4 * (dP(1, 2) * C[2] * C[2] + dP(1, 1) * C[1] * C[1])}}; // clang-format on Matrix<Real> dNx3 = { {-3. / 4 * (dP(0, 0) * C[0] * S[0] + dP(0, 2) * C[2] * S[2]), -3. / 4 * (dP(0, 1) * C[1] * S[1] + dP(0, 0) * C[0] * S[0]), -3. / 4 * (dP(0, 2) * C[2] * S[2] + dP(0, 1) * C[1] * S[1])}, {-3. / 4 * (dP(1, 0) * C[0] * S[0] + dP(1, 2) * C[2] * S[2]), -3. / 4 * (dP(1, 1) * C[1] * S[1] + dP(1, 0) * C[0] * S[0]), -3. / 4 * (dP(1, 2) * C[2] * S[2] + dP(1, 1) * C[1] * S[1])}}; Matrix<Real> dNy1 = { {3. / 2 * (dP(0, 0) * S[0] / L[0] - dP(0, 2) * S[2] / L[2]), 3. / 2 * (dP(0, 1) * S[1] / L[1] - dP(0, 0) * S[0] / L[0]), 3. / 2 * (dP(0, 2) * S[2] / L[2] - dP(0, 1) * S[1] / L[1])}, {3. / 2 * (dP(1, 0) * S[0] / L[0] - dP(1, 2) * S[2] / L[2]), 3. / 2 * (dP(1, 1) * S[1] / L[1] - dP(1, 0) * S[0] / L[0]), 3. / 2 * (dP(1, 2) * S[2] / L[2] - dP(1, 1) * S[1] / L[1])}}; Matrix<Real> dNy2 = dNx3; Matrix<Real> dNy3 = { // clang-format off {-1 - 3. / 4 * (dP(0, 0) * S[0] * S[0] + dP(0, 2) * S[2] * S[2]), 1 - 3. / 4 * (dP(0, 1) * S[1] * S[1] + dP(0, 0) * S[0] * S[0]), - 3. / 4 * (dP(0, 2) * S[2] * S[2] + dP(0, 1) * S[1] * S[1])}, {-1 - 3. / 4 * (dP(1, 0) * S[0] * S[0] + dP(1, 2) * S[2] * S[2]), - 3. / 4 * (dP(1, 1) * S[1] * S[1] + dP(1, 0) * S[0] * S[0]), 1 - 3. / 4 * (dP(1, 2) * S[2] * S[2] + dP(1, 1) * S[1] * S[1])}}; // clang-format on // Derivative of linear (membrane mode) functions Matrix<Real> dNm(2, 3); InterpolationElement<_itp_lagrange_triangle_3, _itk_lagrangian>::computeDNDS( natural_coords, dNm); UInt i = 0; for (const Matrix<Real> & mat : {dNm, dNx1, dNx2, dNx3, dNy1, dNy2, dNy3}) { B.block(mat, 0, i); i += mat.cols(); } } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_discrete_kirchhoff_triangle_18, _itk_structural>::arrangeInVoigt(const Matrix<Real> & dnds, Matrix<Real> & B) { Matrix<Real> dNm(2, 3), dNx1(2, 3), dNx2(2, 3), dNx3(2, 3), dNy1(2, 3), dNy2(2, 3), dNy3(2, 3); UInt i = 0; for (Matrix<Real> * mat : {&dNm, &dNx1, &dNx2, &dNx3, &dNy1, &dNy2, &dNy3}) { *mat = dnds.block(0, i, 2, 3); i += mat->cols(); } for (UInt i = 0; i < 3; ++i) { // clang-format off Matrix<Real> Bm = {{dNm(0, i), 0, 0, 0, 0, 0}, {0, dNm(1, i), 0, 0, 0, 0}, {dNm(1, i), dNm(0, i), 0, 0, 0, 0}}; Matrix<Real> Bf = {{0, 0, dNx1(0, i), -dNx3(0, i), dNx2(0, i), 0}, {0, 0, dNy1(1, i), -dNy3(1, i), dNy2(1, i), 0}, {0, 0, dNx1(1, i) + dNy1(0, i), -dNx3(1, i) - dNy3(0, i), dNx2(1, i) + dNy2(0, i), 0}}; // clang-format on B.block(Bm, 0, i * 6); B.block(Bf, 3, i * 6); } } } // namespace akantu #endif /* __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.cc b/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.cc index 55b8b9d92..74b08b40c 100644 --- a/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.cc @@ -1,173 +1,173 @@ /** * @file element_class_pentahedron_15_inline_impl.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Sacha Laffely <sacha.laffely@epfl.ch> * @author Damien Scantamburlo <damien.scantamburlo@epfl.ch> * * @date creation: Tue Mar 31 2015 - * @date last modification: Wed Sep 16 2015 + * @date last modification: Thu Dec 28 2017 * * @brief Specialization of the element_class class for the type -_pentahedron_15 + * _pentahedron_15 * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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. +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. +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 <http://www.gnu.org/licenses/>. +along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim z ^ | | | 1 | /|\ |/ | \ 10 7 6 / | \ / | \ 4 2--8--0 | \ / / | \11 / 13 12 9---------->y | / \ / |/ \ / 5--14--3 / / / v x x y z * N0 -1 1 0 * N1 -1 0 1 * N2 -1 0 0 * N3 1 1 0 * N4 1 0 1 * N5 1 0 0 * N6 -1 0.5 0.5 * N7 -1 0 0.5 * N8 -1 0.5 0 * N9 0 1 0 * N10 0 0 1 * N11 0 0 0 * N12 1 0.5 0.5 * N13 1 0 0.5 * N14 1 0.5 0 */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_pentahedron_15, _gt_pentahedron_15, _itp_lagrange_pentahedron_15, _ek_regular, 3, _git_pentahedron, 2); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_pentahedron_15>::computeShapes( const vector_type & c, vector_type & N) { auto & x = c(0); auto & y = c(1); auto & z = c(2); // Shape Functions, Natural coordinates N(0) = 0.5 * y * (1 - x) * (2 * y - 2 - x); N(1) = 0.5 * z * (1 - x) * (2 * z - 2 - x); N(2) = 0.5 * (x - 1) * (1 - y - z) * (x + 2 * y + 2 * z); N(3) = 0.5 * y * (1 + x) * (2 * y - 2 + x); N(4) = 0.5 * z * (1 + x) * (2 * z - 2 + x); N(5) = 0.5 * (-x - 1) * (1 - y - z) * (-x + 2 * y + 2 * z); N(6) = 2.0 * y * z * (1 - x); N(7) = 2.0 * z * (1 - y - z) * (1 - x); N(8) = 2.0 * y * (1 - x) * (1 - y - z); N(9) = y * (1 - x * x); N(10) = z * (1 - x * x); N(11) = (1 - y - z) * (1 - x * x); N(12) = 2.0 * y * z * (1 + x); N(13) = 2.0 * z * (1 - y - z) * (1 + x); N(14) = 2.0 * y * (1 - y - z) * (1 + x); } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_pentahedron_15>::computeDNDS( const vector_type & c, matrix_type & dnds) { auto & x = c(0); auto & y = c(1); auto & z = c(2); // ddx dnds(0, 0) = 0.5 * y * (2 * x - 2 * y + 1); dnds(0, 1) = 0.5 * z * (2 * x - 2 * z + 1); dnds(0, 2) = -0.5 * (2 * x + 2 * y + 2 * z - 1) * (y + z - 1); dnds(0, 3) = 0.5 * y * (2 * x + 2 * y - 1); dnds(0, 4) = 0.5 * z * (2 * x + 2 * z - 1); dnds(0, 5) = -0.5 * (y + z - 1) * (2 * x - 2 * y - 2 * z + 1); dnds(0, 6) = -2.0 * y * z; dnds(0, 7) = 2.0 * z * (y + z - 1); dnds(0, 8) = 2.0 * y * (y + z - 1); dnds(0, 9) = -2.0 * x * y; dnds(0, 10) = -2.0 * x * z; dnds(0, 11) = 2.0 * x * (y + z - 1); dnds(0, 12) = 2.0 * y * z; dnds(0, 13) = -2.0 * z * (y + z - 1); dnds(0, 14) = -2.0 * y * (y + z - 1); // ddy dnds(1, 0) = -0.5 * (x - 1) * (4 * y - x - 2); dnds(1, 1) = 0.0; dnds(1, 2) = -0.5 * (x - 1) * (4 * y + x + 2 * (2 * z - 1)); dnds(1, 3) = 0.5 * (x + 1) * (4 * y + x - 2); dnds(1, 4) = 0.0; dnds(1, 5) = 0.5 * (x + 1) * (4 * y - x + 2 * (2 * z - 1)); dnds(1, 6) = -2.0 * (x - 1) * z; dnds(1, 7) = 2.0 * z * (x - 1); dnds(1, 8) = 2.0 * (2 * y + z - 1) * (x - 1); dnds(1, 9) = -(x * x - 1); dnds(1, 10) = 0.0; dnds(1, 11) = (x * x - 1); dnds(1, 12) = 2.0 * z * (x + 1); dnds(1, 13) = -2.0 * z * (x + 1); dnds(1, 14) = -2.0 * (2 * y + z - 1) * (x + 1); // ddz dnds(2, 0) = 0.0; dnds(2, 1) = -0.5 * (x - 1) * (4 * z - x - 2); dnds(2, 2) = -0.5 * (x - 1) * (4 * z + x + 2 * (2 * y - 1)); dnds(2, 3) = 0.0; dnds(2, 4) = 0.5 * (x + 1) * (4 * z + x - 2); dnds(2, 5) = 0.5 * (x + 1) * (4 * z - x + 2 * (2 * y - 1)); dnds(2, 6) = -2.0 * (x - 1) * y; dnds(2, 7) = 2.0 * (x - 1) * (2 * z + y - 1); dnds(2, 8) = 2.0 * y * (x - 1); dnds(2, 9) = 0.0; dnds(2, 10) = -(x * x - 1); dnds(2, 11) = (x * x - 1); dnds(2, 12) = 2.0 * (x + 1) * y; dnds(2, 13) = -2.0 * (x + 1) * (2 * z + y - 1); dnds(2, 14) = -2.0 * (x + 1) * y; } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_pentahedron_15>::getInradius( const Matrix<Real> & coord) { return GeometricalElement<_gt_pentahedron_6>::getInradius(coord); } diff --git a/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.cc b/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.cc index 806c0370b..1f7de539e 100644 --- a/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.cc @@ -1,128 +1,127 @@ /** * @file element_class_pentahedron_6_inline_impl.cc * * @author Marion Estelle Chambart <mchambart@stucky.ch> * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Thomas Menouillard <tmenouillard@stucky.ch> * * @date creation: Mon Mar 14 2011 - * @date last modification: Tue Sep 01 2015 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _pentahedron_6 * * @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) + * Copyright (©) 2010-2018 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. +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. +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 <http://www.gnu.org/licenses/>. +along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim /z | | | 1 | /|\ |/ | \ / | \ / | \ / | \ 4 2-----0 | \ / / | \/ / | \ /----------/y | / \ / |/ \ / 5---.--3 / / / \x x y z * N0 -1 1 0 * N1 -1 0 1 * N2 -1 0 0 * N3 1 1 0 * N4 1 0 1 * N5 1 0 0 */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_pentahedron_6, _gt_pentahedron_6, _itp_lagrange_pentahedron_6, _ek_regular, 3, _git_pentahedron, 1); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_pentahedron_6>::computeShapes( const vector_type & c, vector_type & N) { /// Natural coordinates N(0) = 0.5 * c(1) * (1 - c(0)); // N1(q) N(1) = 0.5 * c(2) * (1 - c(0)); // N2(q) N(2) = 0.5 * (1 - c(1) - c(2)) * (1 - c(0)); // N3(q) N(3) = 0.5 * c(1) * (1 + c(0)); // N4(q) N(4) = 0.5 * c(2) * (1 + c(0)); // N5(q) N(5) = 0.5 * (1 - c(1) - c(2)) * (1 + c(0)); // N6(q) } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_pentahedron_6>::computeDNDS( const vector_type & c, matrix_type & dnds) { dnds(0, 0) = -0.5 * c(1); dnds(0, 1) = -0.5 * c(2); dnds(0, 2) = -0.5 * (1 - c(1) - c(2)); dnds(0, 3) = 0.5 * c(1); dnds(0, 4) = 0.5 * c(2); dnds(0, 5) = 0.5 * (1 - c(1) - c(2)); dnds(1, 0) = 0.5 * (1 - c(0)); dnds(1, 1) = 0.0; dnds(1, 2) = -0.5 * (1 - c(0)); dnds(1, 3) = 0.5 * (1 + c(0)); dnds(1, 4) = 0.0; dnds(1, 5) = -0.5 * (1 + c(0)); dnds(2, 0) = 0.0; dnds(2, 1) = 0.5 * (1 - c(0)); dnds(2, 2) = -0.5 * (1 - c(0)); dnds(2, 3) = 0.0; dnds(2, 4) = 0.5 * (1 + c(0)); dnds(2, 5) = -0.5 * (1 + c(0)); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_pentahedron_6>::getInradius(const Matrix<Real> & coord) { Vector<Real> u0 = coord(0); Vector<Real> u1 = coord(1); Vector<Real> u2 = coord(2); Vector<Real> u3 = coord(3); Real a = u0.distance(u1); Real b = u1.distance(u2); Real c = u2.distance(u3); Real d = u3.distance(u0); Real s = (a + b + c) / 2; Real A = std::sqrt(s * (s - a) * (s - b) * (s - c)); Real ra = 2 * s / A; Real p = std::min(ra, d); return p; } diff --git a/src/fe_engine/element_classes/element_class_point_1_inline_impl.cc b/src/fe_engine/element_classes/element_class_point_1_inline_impl.cc index ff0fbb514..838767d4f 100644 --- a/src/fe_engine/element_classes/element_class_point_1_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_point_1_inline_impl.cc @@ -1,79 +1,78 @@ /** * @file element_class_point_1_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _point_1 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim x (0) @endverbatim * * @subsection shapes Shape functions * @f{eqnarray*}{ * N1 &=& 1 * @f} * * @subsection quad_points Position of quadrature points * @f{eqnarray*}{ * q_0 &=& 0 * @f} */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_point_1, _gt_point, _itp_lagrange_point_1, _ek_regular, 0, _git_point, 1); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_point_1>::computeShapes( __attribute__((unused)) const vector_type & natural_coords, vector_type & N) { N(0) = 1; /// N1(q_0) } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_point_1>::computeDNDS( __attribute__((unused)) const vector_type & natural_coords, __attribute__((unused)) matrix_type & dnds) {} /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_lagrange_point_1>::computeSpecialJacobian( __attribute__((unused)) const Matrix<Real> & J, Real & jac) { jac = 0.; } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_point>::getInradius(__attribute__((unused)) const Matrix<Real> & coord) { return 0.; } diff --git a/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.cc b/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.cc index f204bc660..db3a606ad 100644 --- a/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.cc @@ -1,155 +1,154 @@ /** * @file element_class_quadrangle_4_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 - * @date last modification: Mon Dec 08 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _quadrangle_4 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \eta ^ (-1,1) | (1,1) x---------x | | | | | | --|---------|-----> \xi | | | | | | x---------x (-1,-1) | (1,-1) @endverbatim * * @subsection shapes Shape functions * @f[ * \begin{array}{lll} * N1 = (1 - \xi) (1 - \eta) / 4 * & \frac{\partial N1}{\partial \xi} = - (1 - \eta) / 4 * & \frac{\partial N1}{\partial \eta} = - (1 - \xi) / 4 \\ * N2 = (1 + \xi) (1 - \eta) / 4 \\ * & \frac{\partial N2}{\partial \xi} = (1 - \eta) / 4 * & \frac{\partial N2}{\partial \eta} = - (1 + \xi) / 4 \\ * N3 = (1 + \xi) (1 + \eta) / 4 \\ * & \frac{\partial N3}{\partial \xi} = (1 + \eta) / 4 * & \frac{\partial N3}{\partial \eta} = (1 + \xi) / 4 \\ * N4 = (1 - \xi) (1 + \eta) / 4 * & \frac{\partial N4}{\partial \xi} = - (1 + \eta) / 4 * & \frac{\partial N4}{\partial \eta} = (1 - \xi) / 4 \\ * \end{array} * @f] * * @subsection quad_points Position of quadrature points * @f{eqnarray*}{ * \xi_{q0} &=& 0 \qquad \eta_{q0} = 0 * @f} */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_quadrangle_4, _gt_quadrangle_4, _itp_lagrange_quadrangle_4, _ek_regular, 2, _git_segment, 2); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_quadrangle_4>::computeShapes( const vector_type & c, vector_type & N) { N(0) = 1. / 4. * (1. - c(0)) * (1. - c(1)); /// N1(q_0) N(1) = 1. / 4. * (1. + c(0)) * (1. - c(1)); /// N2(q_0) N(2) = 1. / 4. * (1. + c(0)) * (1. + c(1)); /// N3(q_0) N(3) = 1. / 4. * (1. - c(0)) * (1. + c(1)); /// N4(q_0) } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_quadrangle_4>::computeDNDS( const vector_type & c, matrix_type & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial * N4}{\partial \xi}\\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial * N4}{\partial \eta} * \end{array} * \right) * @f] */ dnds(0, 0) = -1. / 4. * (1. - c(1)); dnds(0, 1) = 1. / 4. * (1. - c(1)); dnds(0, 2) = 1. / 4. * (1. + c(1)); dnds(0, 3) = -1. / 4. * (1. + c(1)); dnds(1, 0) = -1. / 4. * (1. - c(0)); dnds(1, 1) = -1. / 4. * (1. + c(0)); dnds(1, 2) = 1. / 4. * (1. + c(0)); dnds(1, 3) = 1. / 4. * (1. - c(0)); } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_lagrange_quadrangle_4>::computeSpecialJacobian( const Matrix<Real> & J, Real & jac) { Vector<Real> vprod(J.cols()); Matrix<Real> Jt(J.transpose(), true); vprod.crossProduct(Jt(0), Jt(1)); jac = vprod.norm(); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_quadrangle_4>::getInradius(const Matrix<Real> & coord) { Vector<Real> u0 = coord(0); Vector<Real> u1 = coord(1); Vector<Real> u2 = coord(2); Vector<Real> u3 = coord(3); Real a = u0.distance(u1); Real b = u1.distance(u2); Real c = u2.distance(u3); Real d = u3.distance(u0); // Real septimetre = (a + b + c + d) / 2.; // Real p = Math::distance_2d(coord + 0, coord + 4); // Real q = Math::distance_2d(coord + 2, coord + 6); // Real area = sqrt(4*(p*p * q*q) - (a*a + b*b + c*c + d*d)*(a*a + c*c - b*b - // d*d)) / 4.; // Real h = sqrt(area); // to get a length // Real h = area / septimetre; // formula of inradius for circumscritable // quadrelateral Real h = std::min(a, std::min(b, std::min(c, d))); return h; } diff --git a/src/fe_engine/element_classes/element_class_quadrangle_8_inline_impl.cc b/src/fe_engine/element_classes/element_class_quadrangle_8_inline_impl.cc index df4f635ca..632d27125 100644 --- a/src/fe_engine/element_classes/element_class_quadrangle_8_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_quadrangle_8_inline_impl.cc @@ -1,186 +1,185 @@ /** * @file element_class_quadrangle_8_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed May 18 2011 - * @date last modification: Tue Apr 07 2015 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the ElementClass for the _quadrangle_8 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \eta ^ | (-1,1) (0,1) (1,1) x-------x-------x | | | | | | | | | (-1,0)| | |(1,0) ----x---------------X-----> \xi | | | | | | | | | | | | x-------x-------x (-1,-1) (0,-1) (1,-1) | @endverbatim * * @subsection shapes Shape functions * @f[ * \begin{array}{lll} * N1 = (1 - \xi) (1 - \eta)(- 1 - \xi - \eta) / 4 * & \frac{\partial N1}{\partial \xi} = (1 - \eta)(2 \xi + \eta) / 4 * & \frac{\partial N1}{\partial \eta} = (1 - \xi)(\xi + 2 \eta) / 4 \\ * N2 = (1 + \xi) (1 - \eta)(- 1 + \xi - \eta) / 4 \\ * & \frac{\partial N2}{\partial \xi} = (1 - \eta)(2 \xi - \eta) / 4 * & \frac{\partial N2}{\partial \eta} = - (1 + \xi)(\xi - 2 \eta) / 4 \\ * N3 = (1 + \xi) (1 + \eta)(- 1 + \xi + \eta) / 4 \\ * & \frac{\partial N3}{\partial \xi} = (1 + \eta)(2 \xi + \eta) / 4 * & \frac{\partial N3}{\partial \eta} = (1 + \xi)(\xi + 2 \eta) / 4 \\ * N4 = (1 - \xi) (1 + \eta)(- 1 - \xi + \eta) / 4 * & \frac{\partial N4}{\partial \xi} = (1 + \eta)(2 \xi - \eta) / 4 * & \frac{\partial N4}{\partial \eta} = - (1 - \xi)(\xi - 2 \eta) / 4 \\ * N5 = (1 - \xi^2) (1 - \eta) / 2 * & \frac{\partial N1}{\partial \xi} = - \xi (1 - \eta) * & \frac{\partial N1}{\partial \eta} = - (1 - \xi^2) / 2 \\ * N6 = (1 + \xi) (1 - \eta^2) / 2 \\ * & \frac{\partial N2}{\partial \xi} = (1 - \eta^2) / 2 * & \frac{\partial N2}{\partial \eta} = - \eta (1 + \xi) \\ * N7 = (1 - \xi^2) (1 + \eta) / 2 \\ * & \frac{\partial N3}{\partial \xi} = - \xi (1 + \eta) * & \frac{\partial N3}{\partial \eta} = (1 - \xi^2) / 2 \\ * N8 = (1 - \xi) (1 - \eta^2) / 2 * & \frac{\partial N4}{\partial \xi} = - (1 - \eta^2) / 2 * & \frac{\partial N4}{\partial \eta} = - \eta (1 - \xi) \\ * \end{array} * @f] * * @subsection quad_points Position of quadrature points * @f{eqnarray*}{ * \xi_{q0} &=& 0 \qquad \eta_{q0} = 0 * @f} */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_quadrangle_8, _gt_quadrangle_8, _itp_serendip_quadrangle_8, _ek_regular, 2, _git_segment, 3); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_serendip_quadrangle_8>::computeShapes( const vector_type & c, vector_type & N) { /// Natural coordinates const Real xi = c(0); const Real eta = c(1); N(0) = .25 * (1 - xi) * (1 - eta) * (-1 - xi - eta); N(1) = .25 * (1 + xi) * (1 - eta) * (-1 + xi - eta); N(2) = .25 * (1 + xi) * (1 + eta) * (-1 + xi + eta); N(3) = .25 * (1 - xi) * (1 + eta) * (-1 - xi + eta); N(4) = .5 * (1 - xi * xi) * (1 - eta); N(5) = .5 * (1 + xi) * (1 - eta * eta); N(6) = .5 * (1 - xi * xi) * (1 + eta); N(7) = .5 * (1 - xi) * (1 - eta * eta); } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_serendip_quadrangle_8>::computeDNDS( const vector_type & c, matrix_type & dnds) { const Real xi = c(0); const Real eta = c(1); /// dN/dxi dnds(0, 0) = .25 * (1 - eta) * (2 * xi + eta); dnds(0, 1) = .25 * (1 - eta) * (2 * xi - eta); dnds(0, 2) = .25 * (1 + eta) * (2 * xi + eta); dnds(0, 3) = .25 * (1 + eta) * (2 * xi - eta); dnds(0, 4) = -xi * (1 - eta); dnds(0, 5) = .5 * (1 - eta * eta); dnds(0, 6) = -xi * (1 + eta); dnds(0, 7) = -.5 * (1 - eta * eta); /// dN/deta dnds(1, 0) = .25 * (1 - xi) * (2 * eta + xi); dnds(1, 1) = .25 * (1 + xi) * (2 * eta - xi); dnds(1, 2) = .25 * (1 + xi) * (2 * eta + xi); dnds(1, 3) = .25 * (1 - xi) * (2 * eta - xi); dnds(1, 4) = -.5 * (1 - xi * xi); dnds(1, 5) = -eta * (1 + xi); dnds(1, 6) = .5 * (1 - xi * xi); dnds(1, 7) = -eta * (1 - xi); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_quadrangle_8>::getInradius(const Matrix<Real> & coord) { Real a, b, h; Vector<Real> u0 = coord(0); Vector<Real> u1 = coord(1); Vector<Real> u2 = coord(2); Vector<Real> u3 = coord(3); Vector<Real> u4 = coord(4); Vector<Real> u5 = coord(5); Vector<Real> u6 = coord(6); Vector<Real> u7 = coord(7); a = u0.distance(u4); b = u4.distance(u1); h = std::min(a, b); a = u1.distance(u5); b = u5.distance(u2); h = std::min(h, std::min(a, b)); a = u2.distance(u6); b = u6.distance(u3); h = std::min(h, std::min(a, b)); a = u3.distance(u7); b = u7.distance(u0); h = std::min(h, std::min(a, b)); return h; } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_serendip_quadrangle_8>::computeSpecialJacobian( const Matrix<Real> & J, Real & jac) { Vector<Real> vprod(J.cols()); Matrix<Real> Jt(J.transpose(), true); vprod.crossProduct(Jt(0), Jt(1)); jac = vprod.norm(); } diff --git a/src/fe_engine/element_classes/element_class_segment_2_inline_impl.cc b/src/fe_engine/element_classes/element_class_segment_2_inline_impl.cc index 0ac10eca0..60a78a17c 100644 --- a/src/fe_engine/element_classes/element_class_segment_2_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_segment_2_inline_impl.cc @@ -1,105 +1,104 @@ /** * @file element_class_segment_2_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jul 16 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _segment_2 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim q --x--------|--------x---> x -1 0 1 @endverbatim * * @subsection shapes Shape functions * @f{eqnarray*}{ * w_1(x) &=& 1/2(1 - x) \\ * w_2(x) &=& 1/2(1 + x) * @f} * * @subsection quad_points Position of quadrature points * @f{eqnarray*}{ * x_{q} &=& 0 * @f} */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_segment_2, _gt_segment_2, _itp_lagrange_segment_2, _ek_regular, 1, _git_segment, 1); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_segment_2>::computeShapes( const vector_type & natural_coords, vector_type & N) { /// natural coordinate Real c = natural_coords(0); /// shape functions N(0) = 0.5 * (1 - c); N(1) = 0.5 * (1 + c); } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_segment_2>::computeDNDS( __attribute__((unused)) const vector_type & natural_coords, matrix_type & dnds) { /// dN1/de dnds(0, 0) = -.5; /// dN2/de dnds(0, 1) = .5; } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_lagrange_segment_2>::computeSpecialJacobian( const Matrix<Real> & dxds, Real & jac) { jac = dxds.norm<L_2>(); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_segment_2>::getInradius(const Matrix<Real> & coord) { return std::abs(coord(0, 0) - coord(0, 1)); } // /* -------------------------------------------------------------------------- // */ // template<> inline bool ElementClass<_segment_2>::contains(const Vector<Real> // & natural_coords) { // if (natural_coords(0) < -1.) return false; // if (natural_coords(0) > 1.) return false; // return true; // } /* -------------------------------------------------------------------------- */ diff --git a/src/fe_engine/element_classes/element_class_segment_3_inline_impl.cc b/src/fe_engine/element_classes/element_class_segment_3_inline_impl.cc index 710de16f9..3fa470a40 100644 --- a/src/fe_engine/element_classes/element_class_segment_3_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_segment_3_inline_impl.cc @@ -1,106 +1,105 @@ /** * @file element_class_segment_3_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jul 16 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _segment_3 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim -1 0 1 -----x---------x---------x-----> x 1 3 2 @endverbatim * * @subsection coords Nodes coordinates * * @f[ * \begin{array}{lll} * x_{1} = -1 & x_{2} = 1 & x_{3} = 0 * \end{array} * @f] * * @subsection shapes Shape functions * @f[ * \begin{array}{ll} * w_1(x) = \frac{x}{2}(x - 1) & w'_1(x) = x - \frac{1}{2}\\ * w_2(x) = \frac{x}{2}(x + 1) & w'_2(x) = x + \frac{1}{2}\\ * w_3(x) = 1-x^2 & w'_3(x) = -2x * \end{array} * @f] * * @subsection quad_points Position of quadrature points * @f[ * \begin{array}{ll} * x_{q1} = -1/\sqrt{3} & x_{q2} = 1/\sqrt{3} * \end{array} * @f] */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_segment_3, _gt_segment_3, _itp_lagrange_segment_3, _ek_regular, 1, _git_segment, 2); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_segment_3>::computeShapes( const vector_type & natural_coords, vector_type & N) { Real c = natural_coords(0); N(0) = (c - 1) * c / 2; N(1) = (c + 1) * c / 2; N(2) = 1 - c * c; } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_segment_3>::computeDNDS( const vector_type & natural_coords, matrix_type & dnds) { Real c = natural_coords(0); dnds(0, 0) = c - .5; dnds(0, 1) = c + .5; dnds(0, 2) = -2 * c; } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_lagrange_segment_3>::computeSpecialJacobian( const Matrix<Real> & dxds, Real & jac) { jac = Math::norm2(dxds.storage()); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_segment_3>::getInradius(const Matrix<Real> & coord) { Real dist1 = std::abs(coord(0, 0) - coord(0, 1)); Real dist2 = std::abs(coord(0, 1) - coord(0, 2)); return std::min(dist1, dist2); } diff --git a/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.cc b/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.cc index f5dab36fa..f1df60b6e 100644 --- a/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.cc @@ -1,278 +1,277 @@ /** * @file element_class_tetrahedron_10_inline_impl.cc * * @author Peter Spijker <peter.spijker@epfl.ch> * * @date creation: Fri Jul 16 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type - _tetrahedron_10 + * _tetrahedron_10 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \zeta ^ | (0,0,1) x |` . | ` . | ` . | ` . (0,0.5,0.5) | ` x. | q4 o ` . \eta | ` . -, (0,0,0.5) x ` x (0.5,0,0.5) - | ` x-(0,1,0) | q3 o` - ' | (0,0.5,0) - ` ' | x- ` x (0.5,0.5,0) | q1 o - o q2` ' | - ` ' | - ` ' x---------------x--------------` x-----> \xi (0,0,0) (0.5,0,0) (1,0,0) @endverbatim * * @subsection coords Nodes coordinates * * @f[ * \begin{array}{lll} * \xi_{0} = 0 & \eta_{0} = 0 & \zeta_{0} = 0 \\ * \xi_{1} = 1 & \eta_{1} = 0 & \zeta_{1} = 0 \\ * \xi_{2} = 0 & \eta_{2} = 1 & \zeta_{2} = 0 \\ * \xi_{3} = 0 & \eta_{3} = 0 & \zeta_{3} = 1 \\ * \xi_{4} = 1/2 & \eta_{4} = 0 & \zeta_{4} = 0 \\ * \xi_{5} = 1/2 & \eta_{5} = 1/2 & \zeta_{5} = 0 \\ * \xi_{6} = 0 & \eta_{6} = 1/2 & \zeta_{6} = 0 \\ * \xi_{7} = 0 & \eta_{7} = 0 & \zeta_{7} = 1/2 \\ * \xi_{8} = 1/2 & \eta_{8} = 0 & \zeta_{8} = 1/2 \\ * \xi_{9} = 0 & \eta_{9} = 1/2 & \zeta_{9} = 1/2 * \end{array} * @f] * * @subsection shapes Shape functions * @f[ * \begin{array}{llll} * N1 = (1 - \xi - \eta - \zeta) (1 - 2 \xi - 2 \eta - 2 \zeta) * & \frac{\partial N1}{\partial \xi} = 4 \xi + 4 \eta + 4 \zeta - 3 * & \frac{\partial N1}{\partial \eta} = 4 \xi + 4 \eta + 4 \zeta - 3 * & \frac{\partial N1}{\partial \zeta} = 4 \xi + 4 \eta + 4 \zeta - 3 \\ * N2 = \xi (2 \xi - 1) * & \frac{\partial N2}{\partial \xi} = 4 \xi - 1 * & \frac{\partial N2}{\partial \eta} = 0 * & \frac{\partial N2}{\partial \zeta} = 0 \\ * N3 = \eta (2 \eta - 1) * & \frac{\partial N3}{\partial \xi} = 0 * & \frac{\partial N3}{\partial \eta} = 4 \eta - 1 * & \frac{\partial N3}{\partial \zeta} = 0 \\ * N4 = \zeta (2 \zeta - 1) * & \frac{\partial N4}{\partial \xi} = 0 * & \frac{\partial N4}{\partial \eta} = 0 * & \frac{\partial N4}{\partial \zeta} = 4 \zeta - 1 \\ * N5 = 4 \xi (1 - \xi - \eta - \zeta) * & \frac{\partial N5}{\partial \xi} = 4 - 8 \xi - 4 \eta - 4 \zeta * & \frac{\partial N5}{\partial \eta} = -4 \xi * & \frac{\partial N5}{\partial \zeta} = -4 \xi \\ * N6 = 4 \xi \eta * & \frac{\partial N6}{\partial \xi} = 4 \eta * & \frac{\partial N6}{\partial \eta} = 4 \xi * & \frac{\partial N6}{\partial \zeta} = 0 \\ * N7 = 4 \eta (1 - \xi - \eta - \zeta) * & \frac{\partial N7}{\partial \xi} = -4 \eta * & \frac{\partial N7}{\partial \eta} = 4 - 4 \xi - 8 \eta - 4 \zeta * & \frac{\partial N7}{\partial \zeta} = -4 \eta \\ * N8 = 4 \zeta (1 - \xi - \eta - \zeta) * & \frac{\partial N8}{\partial \xi} = -4 \zeta * & \frac{\partial N8}{\partial \eta} = -4 \zeta * & \frac{\partial N8}{\partial \zeta} = 4 - 4 \xi - 4 \eta - 8 \zeta \\ * N9 = 4 \zeta \xi * & \frac{\partial N9}{\partial \xi} = 4 \zeta * & \frac{\partial N9}{\partial \eta} = 0 * & \frac{\partial N9}{\partial \zeta} = 4 \xi \\ * N10 = 4 \eta \zeta * & \frac{\partial N10}{\partial \xi} = 0 * & \frac{\partial N10}{\partial \eta} = 4 \zeta * & \frac{\partial N10}{\partial \zeta} = 4 \eta \\ * \end{array} * @f] * * @subsection quad_points Position of quadrature points * @f[ * a = \frac{5 - \sqrt{5}}{20}\\ * b = \frac{5 + 3 \sqrt{5}}{20} * \begin{array}{lll} * \xi_{q_0} = a & \eta_{q_0} = a & \zeta_{q_0} = a \\ * \xi_{q_1} = b & \eta_{q_1} = a & \zeta_{q_1} = a \\ * \xi_{q_2} = a & \eta_{q_2} = b & \zeta_{q_2} = a \\ * \xi_{q_3} = a & \eta_{q_3} = a & \zeta_{q_3} = b * \end{array} * @f] */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_tetrahedron_10, _gt_tetrahedron_10, _itp_lagrange_tetrahedron_10, _ek_regular, 3, _git_tetrahedron, 2); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_tetrahedron_10>::computeShapes( const vector_type & natural_coords, vector_type & N) { /// Natural coordinates Real xi = natural_coords(0); Real eta = natural_coords(1); Real zeta = natural_coords(2); Real sum = xi + eta + zeta; Real c0 = 1 - sum; Real c1 = 1 - 2 * sum; Real c2 = 2 * xi - 1; Real c3 = 2 * eta - 1; Real c4 = 2 * zeta - 1; /// Shape functions N(0) = c0 * c1; N(1) = xi * c2; N(2) = eta * c3; N(3) = zeta * c4; N(4) = 4 * xi * c0; N(5) = 4 * xi * eta; N(6) = 4 * eta * c0; N(7) = 4 * zeta * c0; N(8) = 4 * xi * zeta; N(9) = 4 * eta * zeta; } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_tetrahedron_10>::computeDNDS( const vector_type & natural_coords, matrix_type & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccccccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial N4}{\partial * \xi} * & \frac{\partial N5}{\partial \xi} & \frac{\partial N6}{\partial * \xi} * & \frac{\partial N7}{\partial \xi} & \frac{\partial N8}{\partial * \xi} * & \frac{\partial N9}{\partial \xi} & \frac{\partial * N10}{\partial \xi} \\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial N4}{\partial * \eta} * & \frac{\partial N5}{\partial \eta} & \frac{\partial N6}{\partial * \eta} * & \frac{\partial N7}{\partial \eta} & \frac{\partial N8}{\partial * \eta} * & \frac{\partial N9}{\partial \eta} & \frac{\partial * N10}{\partial \eta} \\ * \frac{\partial N1}{\partial \zeta} & \frac{\partial N2}{\partial * \zeta} * & \frac{\partial N3}{\partial \zeta} & \frac{\partial N4}{\partial * \zeta} * & \frac{\partial N5}{\partial \zeta} & \frac{\partial N6}{\partial * \zeta} * & \frac{\partial N7}{\partial \zeta} & \frac{\partial N8}{\partial * \zeta} * & \frac{\partial N9}{\partial \zeta} & \frac{\partial * N10}{\partial \zeta} * \end{array} * \right) * @f] */ /// Natural coordinates Real xi = natural_coords(0); Real eta = natural_coords(1); Real zeta = natural_coords(2); Real sum = xi + eta + zeta; /// \frac{\partial N_i}{\partial \xi} dnds(0, 0) = 4 * sum - 3; dnds(0, 1) = 4 * xi - 1; dnds(0, 2) = 0; dnds(0, 3) = 0; dnds(0, 4) = 4 * (1 - sum - xi); dnds(0, 5) = 4 * eta; dnds(0, 6) = -4 * eta; dnds(0, 7) = -4 * zeta; dnds(0, 8) = 4 * zeta; dnds(0, 9) = 0; /// \frac{\partial N_i}{\partial \eta} dnds(1, 0) = 4 * sum - 3; dnds(1, 1) = 0; dnds(1, 2) = 4 * eta - 1; dnds(1, 3) = 0; dnds(1, 4) = -4 * xi; dnds(1, 5) = 4 * xi; dnds(1, 6) = 4 * (1 - sum - eta); dnds(1, 7) = -4 * zeta; dnds(1, 8) = 0; dnds(1, 9) = 4 * zeta; /// \frac{\partial N_i}{\partial \zeta} dnds(2, 0) = 4 * sum - 3; dnds(2, 1) = 0; dnds(2, 2) = 0; dnds(2, 3) = 4 * zeta - 1; dnds(2, 4) = -4 * xi; dnds(2, 5) = 0; dnds(2, 6) = -4 * eta; dnds(2, 7) = 4 * (1 - sum - zeta); dnds(2, 8) = 4 * xi; dnds(2, 9) = 4 * eta; } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_tetrahedron_10>::getInradius( const Matrix<Real> & coord) { // Only take the four corner tetrahedra UInt tetrahedra[4][4] = { {0, 4, 6, 7}, {4, 1, 5, 8}, {6, 5, 2, 9}, {7, 8, 9, 3}}; Real inradius = std::numeric_limits<Real>::max(); for (UInt t = 0; t < 4; t++) { Real ir = Math::tetrahedron_inradius( coord(tetrahedra[t][0]).storage(), coord(tetrahedra[t][1]).storage(), coord(tetrahedra[t][2]).storage(), coord(tetrahedra[t][3]).storage()); inradius = std::min(ir, inradius); } return inradius; } diff --git a/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.cc b/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.cc index 76f6d85bc..5577d6c3b 100644 --- a/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.cc @@ -1,134 +1,133 @@ /** * @file element_class_tetrahedron_4_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jul 16 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _tetrahedron_4 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \eta ^ | x (0,0,1,0) |` | ` ° \xi | ` ° - | ` x (0,0,0,1) | q.` - ' | -` ' | - ` ' | - ` ' x------------------x-----> \zeta (1,0,0,0) (0,1,0,0) @endverbatim * * @subsection shapes Shape functions * @f{eqnarray*}{ * N1 &=& 1 - \xi - \eta - \zeta \\ * N2 &=& \xi \\ * N3 &=& \eta \\ * N4 &=& \zeta * @f} * * @subsection quad_points Position of quadrature points * @f[ * \xi_{q0} = 1/4 \qquad \eta_{q0} = 1/4 \qquad \zeta_{q0} = 1/4 * @f] */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_tetrahedron_4, _gt_tetrahedron_4, _itp_lagrange_tetrahedron_4, _ek_regular, 3, _git_tetrahedron, 1); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_tetrahedron_4>::computeShapes( const vector_type & natural_coords, vector_type & N) { Real c0 = 1 - natural_coords(0) - natural_coords(1) - natural_coords(2); /// @f$ c2 = 1 - \xi - \eta - \zeta @f$ Real c1 = natural_coords(1); /// @f$ c0 = \xi @f$ Real c2 = natural_coords(2); /// @f$ c1 = \eta @f$ Real c3 = natural_coords(0); /// @f$ c2 = \zeta @f$ N(0) = c0; N(1) = c1; N(2) = c2; N(3) = c3; } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_tetrahedron_4>::computeDNDS( __attribute__((unused)) const vector_type & natural_coords, matrix_type & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial N4}{\partial * \xi} \\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial N4}{\partial * \eta} \\ * \frac{\partial N1}{\partial \zeta} & \frac{\partial N2}{\partial * \zeta} * & \frac{\partial N3}{\partial \zeta} & \frac{\partial N4}{\partial * \zeta} * \end{array} * \right) * @f] */ dnds(0, 0) = -1.; dnds(0, 1) = 1.; dnds(0, 2) = 0.; dnds(0, 3) = 0.; dnds(1, 0) = -1.; dnds(1, 1) = 0.; dnds(1, 2) = 1.; dnds(1, 3) = 0.; dnds(2, 0) = -1.; dnds(2, 1) = 0.; dnds(2, 2) = 0.; dnds(2, 3) = 1.; } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_tetrahedron_4>::getInradius(const Matrix<Real> & coord) { return Math::tetrahedron_inradius(coord(0).storage(), coord(1).storage(), coord(2).storage(), coord(3).storage()); } diff --git a/src/fe_engine/element_classes/element_class_triangle_3_inline_impl.cc b/src/fe_engine/element_classes/element_class_triangle_3_inline_impl.cc index 1b17994d1..77ff9458e 100644 --- a/src/fe_engine/element_classes/element_class_triangle_3_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_triangle_3_inline_impl.cc @@ -1,134 +1,133 @@ /** * @file element_class_triangle_3_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jul 16 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _triangle_3 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \eta ^ | x (0,0,1) |` | ` | q ` | ° ` x--------x-----> \xi (1,0,0) (0,1,0) @endverbatim * * @subsection shapes Shape functions * @f{eqnarray*}{ * N1 &=& 1 - \xi - \eta \\ * N2 &=& \xi \\ * N3 &=& \eta * @f} * * @subsection quad_points Position of quadrature points * @f{eqnarray*}{ * \xi_{q0} &=& 1/3 \qquad \eta_{q0} = 1/3 * @f} */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_triangle_3, _gt_triangle_3, _itp_lagrange_triangle_3, _ek_regular, 2, _git_triangle, 1); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_triangle_3>::computeShapes( const vector_type & natural_coords, vector_type & N) { /// Natural coordinates Real c0 = 1 - natural_coords(0) - natural_coords(1); /// @f$ c0 = 1 - \xi - \eta @f$ Real c1 = natural_coords(0); /// @f$ c1 = \xi @f$ Real c2 = natural_coords(1); /// @f$ c2 = \eta @f$ N(0) = c0; /// N1(q_0) N(1) = c1; /// N2(q_0) N(2) = c2; /// N3(q_0) } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_triangle_3>::computeDNDS( __attribute__((unused)) const vector_type & natural_coords, matrix_type & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} & \frac{\partial N3}{\partial \xi} \\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} & \frac{\partial N3}{\partial \eta} * \end{array} * \right) * @f] */ dnds(0, 0) = -1.; dnds(0, 1) = 1.; dnds(0, 2) = 0.; dnds(1, 0) = -1.; dnds(1, 1) = 0.; dnds(1, 2) = 1.; } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_lagrange_triangle_3>::computeSpecialJacobian( const Matrix<Real> & J, Real & jac) { Vector<Real> vprod(J.cols()); Matrix<Real> Jt(J.transpose(), true); vprod.crossProduct(Jt(0), Jt(1)); jac = vprod.norm(); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_triangle_3>::getInradius(const Matrix<Real> & coord) { return Math::triangle_inradius(coord(0).storage(), coord(1).storage(), coord(2).storage()); } /* -------------------------------------------------------------------------- */ // template<> inline bool ElementClass<_triangle_3>::contains(const Vector<Real> // & natural_coords) { // if (natural_coords[0] < 0.) return false; // if (natural_coords[0] > 1.) return false; // if (natural_coords[1] < 0.) return false; // if (natural_coords[1] > 1.) return false; // if (natural_coords[0]+natural_coords[1] > 1.) return false; // return true; // } /* -------------------------------------------------------------------------- */ diff --git a/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.cc b/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.cc index 7ccb1a5a3..aa8b3a53d 100644 --- a/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.cc @@ -1,200 +1,199 @@ /** * @file element_class_triangle_6_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jul 16 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Oct 11 2017 * * @brief Specialization of the element_class class for the type _triangle_6 * * @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) + * Copyright (©) 2010-2018 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. + 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. + 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 <http://www.gnu.org/licenses/>. + along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim \eta ^ | x 2 | ` | ` | . ` | q2 ` 5 x x 4 | ` | ` | .q0 q1. ` | ` x---------x---------x-----> \xi 0 3 1 @endverbatim * * @subsection coords Nodes coordinates * * @f[ * \begin{array}{ll} * \xi_{0} = 0 & \eta_{0} = 0 \\ * \xi_{1} = 1 & \eta_{1} = 0 \\ * \xi_{2} = 0 & \eta_{2} = 1 \\ * \xi_{3} = 1/2 & \eta_{3} = 0 \\ * \xi_{4} = 1/2 & \eta_{4} = 1/2 \\ * \xi_{5} = 0 & \eta_{5} = 1/2 * \end{array} * @f] * * @subsection shapes Shape functions * @f[ * \begin{array}{lll} * N1 = -(1 - \xi - \eta) (1 - 2 (1 - \xi - \eta)) * & \frac{\partial N1}{\partial \xi} = 1 - 4(1 - \xi - \eta) * & \frac{\partial N1}{\partial \eta} = 1 - 4(1 - \xi - \eta) \\ * N2 = - \xi (1 - 2 \xi) * & \frac{\partial N2}{\partial \xi} = - 1 + 4 \xi * & \frac{\partial N2}{\partial \eta} = 0 \\ * N3 = - \eta (1 - 2 \eta) * & \frac{\partial N3}{\partial \xi} = 0 * & \frac{\partial N3}{\partial \eta} = - 1 + 4 \eta \\ * N4 = 4 \xi (1 - \xi - \eta) * & \frac{\partial N4}{\partial \xi} = 4 (1 - 2 \xi - \eta) * & \frac{\partial N4}{\partial \eta} = - 4 \xi \\ * N5 = 4 \xi \eta * & \frac{\partial N5}{\partial \xi} = 4 \eta * & \frac{\partial N5}{\partial \eta} = 4 \xi \\ * N6 = 4 \eta (1 - \xi - \eta) * & \frac{\partial N6}{\partial \xi} = - 4 \eta * & \frac{\partial N6}{\partial \eta} = 4 (1 - \xi - 2 \eta) * \end{array} * @f] * * @subsection quad_points Position of quadrature points * @f{eqnarray*}{ * \xi_{q0} &=& 1/6 \qquad \eta_{q0} = 1/6 \\ * \xi_{q1} &=& 2/3 \qquad \eta_{q1} = 1/6 \\ * \xi_{q2} &=& 1/6 \qquad \eta_{q2} = 2/3 * @f} */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_triangle_6, _gt_triangle_6, _itp_lagrange_triangle_6, _ek_regular, 2, _git_triangle, 2); /* -------------------------------------------------------------------------- */ template <> template <class vector_type> inline void InterpolationElement<_itp_lagrange_triangle_6>::computeShapes( const vector_type & natural_coords, vector_type & N) { /// Natural coordinates Real c0 = 1 - natural_coords(0) - natural_coords(1); /// @f$ c0 = 1 - \xi - \eta @f$ Real c1 = natural_coords(0); /// @f$ c1 = \xi @f$ Real c2 = natural_coords(1); /// @f$ c2 = \eta @f$ N(0) = c0 * (2 * c0 - 1.); N(1) = c1 * (2 * c1 - 1.); N(2) = c2 * (2 * c2 - 1.); N(3) = 4 * c0 * c1; N(4) = 4 * c1 * c2; N(5) = 4 * c2 * c0; } /* -------------------------------------------------------------------------- */ template <> template <class vector_type, class matrix_type> inline void InterpolationElement<_itp_lagrange_triangle_6>::computeDNDS( const vector_type & natural_coords, matrix_type & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccc} * \frac{\partial N1}{\partial \xi} * & \frac{\partial N2}{\partial \xi} * & \frac{\partial N3}{\partial \xi} * & \frac{\partial N4}{\partial \xi} * & \frac{\partial N5}{\partial \xi} * & \frac{\partial N6}{\partial \xi} \\ * * \frac{\partial N1}{\partial \eta} * & \frac{\partial N2}{\partial \eta} * & \frac{\partial N3}{\partial \eta} * & \frac{\partial N4}{\partial \eta} * & \frac{\partial N5}{\partial \eta} * & \frac{\partial N6}{\partial \eta} * \end{array} * \right) * @f] */ /// Natural coordinates Real c0 = 1 - natural_coords(0) - natural_coords(1); /// @f$ c0 = 1 - \xi - \eta @f$ Real c1 = natural_coords(0); /// @f$ c1 = \xi @f$ Real c2 = natural_coords(1); /// @f$ c2 = \eta @f$ dnds(0, 0) = 1 - 4 * c0; dnds(0, 1) = 4 * c1 - 1.; dnds(0, 2) = 0.; dnds(0, 3) = 4 * (c0 - c1); dnds(0, 4) = 4 * c2; dnds(0, 5) = -4 * c2; dnds(1, 0) = 1 - 4 * c0; dnds(1, 1) = 0.; dnds(1, 2) = 4 * c2 - 1.; dnds(1, 3) = -4 * c1; dnds(1, 4) = 4 * c1; dnds(1, 5) = 4 * (c0 - c2); } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_lagrange_triangle_6>::computeSpecialJacobian( const Matrix<Real> & J, Real & jac) { Vector<Real> vprod(J.cols()); Matrix<Real> Jt(J.transpose(), true); vprod.crossProduct(Jt(0), Jt(1)); jac = vprod.norm(); } /* -------------------------------------------------------------------------- */ template <> inline Real GeometricalElement<_gt_triangle_6>::getInradius(const Matrix<Real> & coord) { UInt triangles[4][3] = {{0, 3, 5}, {3, 1, 4}, {3, 4, 5}, {5, 4, 2}}; Real inradius = std::numeric_limits<Real>::max(); for (UInt t = 0; t < 4; t++) { Real ir = Math::triangle_inradius(coord(triangles[t][0]).storage(), coord(triangles[t][1]).storage(), coord(triangles[t][2]).storage()); inradius = std::min(ir, inradius); } return inradius; } /* -------------------------------------------------------------------------- */ // template<> inline bool ElementClass<_triangle_6>::contains(const Vector<Real> // & natural_coords) { // return ElementClass<_triangle_3>::contains(natural_coords); // } diff --git a/src/fe_engine/element_type_conversion.hh b/src/fe_engine/element_type_conversion.hh index bf9ac699e..124ad9c77 100644 --- a/src/fe_engine/element_type_conversion.hh +++ b/src/fe_engine/element_type_conversion.hh @@ -1,55 +1,57 @@ /** * @file element_type_conversion.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Thu Jul 27 2017 + * @date creation: Fri Jun 18 2010 + * @date last modification: Fri Aug 11 2017 * - * @brief conversion between different types + * @brief conversion between different types * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_TYPE_CONVERSION_HH__ #define __AKANTU_ELEMENT_TYPE_CONVERSION_HH__ namespace akantu { template <class InType, class OutType> OutType convertType(const InType &) { return OutType(); } template <> inline InterpolationType convertType<ElementType, InterpolationType>(const ElementType & type) { InterpolationType itp_type = _itp_not_defined; #define GET_ITP(type) itp_type = ElementClassProperty<type>::interpolation_type; AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_ITP); #undef GET_ITP return itp_type; } } // namespace akantu #endif /* __AKANTU_ELEMENT_TYPE_CONVERSION_HH__ */ diff --git a/src/fe_engine/fe_engine.cc b/src/fe_engine/fe_engine.cc index 95a2d29a2..23bc02714 100644 --- a/src/fe_engine/fe_engine.cc +++ b/src/fe_engine/fe_engine.cc @@ -1,95 +1,94 @@ /** * @file fe_engine.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 20 2010 - * @date last modification: Fri Dec 11 2015 + * @date last modification: Thu Feb 01 2018 * * @brief Implementation of the FEEngine 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "aka_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ FEEngine::FEEngine(Mesh & mesh, UInt element_dimension, const ID & id, MemoryID memory_id) : Memory(id, memory_id), mesh(mesh), normals_on_integration_points("normals_on_quad_points", id, memory_id) { AKANTU_DEBUG_IN(); this->element_dimension = (element_dimension != _all_dimensions) ? element_dimension : mesh.getSpatialDimension(); this->mesh.registerEventHandler(*this, _ehp_fe_engine); init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FEEngine::init() {} /* -------------------------------------------------------------------------- */ FEEngine::~FEEngine() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ typename FEEngine::ElementTypesIteratorHelper FEEngine::elementTypes(UInt dim, GhostType ghost_type, ElementKind kind) const { return this->getIntegratorInterface().getJacobians().elementTypes( dim, ghost_type, kind); } /* -------------------------------------------------------------------------- */ void FEEngine::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "FEEngine [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + element dimension : " << element_dimension << std::endl; stream << space << " + mesh [" << std::endl; mesh.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/fe_engine/fe_engine.hh b/src/fe_engine/fe_engine.hh index 4decb1828..1c0516a8f 100644 --- a/src/fe_engine/fe_engine.hh +++ b/src/fe_engine/fe_engine.hh @@ -1,393 +1,393 @@ /** * @file fe_engine.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Tue Feb 20 2018 * * @brief FEM 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "element_type_map.hh" #include "mesh_events.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FE_ENGINE_HH__ #define __AKANTU_FE_ENGINE_HH__ namespace akantu { class Mesh; class Integrator; class ShapeFunctions; class DOFManager; class Element; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /** * The generic FEEngine class derived in a FEEngineTemplate class * containing the * shape functions and the integration method */ class FEEngine : protected Memory, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: FEEngine(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "fem", MemoryID memory_id = 0); ~FEEngine() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// pre-compute all the shape functions, their derivatives and the jacobians virtual void initShapeFunctions(const GhostType & ghost_type = _not_ghost) = 0; /// extract the nodal values and store them per element template <typename T> static void extractNodalToElementField( const Mesh & mesh, const Array<T> & nodal_f, Array<T> & elemental_f, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter); /// filter a field template <typename T> static void filterElementalData(const Mesh & mesh, const Array<T> & quad_f, Array<T> & filtered_f, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter); /* ------------------------------------------------------------------------ */ /* Integration method bridges */ /* ------------------------------------------------------------------------ */ /// integrate f for all elements of type "type" virtual void integrate(const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// integrate a scalar value f on all elements of type "type" virtual Real integrate(const Array<Real> & f, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// integrate f for all integration points of type "type" but don't sum over /// all integration points virtual void integrateOnIntegrationPoints( const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// integrate one element scalar value on all elements of type "type" virtual Real integrate(const Vector<Real> & f, const ElementType & type, UInt index, const GhostType & ghost_type = _not_ghost) const = 0; /* ------------------------------------------------------------------------ */ /* compatibility with old FEEngine fashion */ /* ------------------------------------------------------------------------ */ #ifndef SWIG /// get the number of integration points virtual UInt getNbIntegrationPoints(const ElementType & type, const GhostType & ghost_type = _not_ghost) const = 0; /// get the precomputed shapes const virtual Array<Real> & getShapes(const ElementType & type, const GhostType & ghost_type = _not_ghost, UInt id = 0) const = 0; /// get the derivatives of shapes const virtual Array<Real> & getShapesDerivatives(const ElementType & type, const GhostType & ghost_type = _not_ghost, UInt id = 0) const = 0; /// get integration points const virtual Matrix<Real> & getIntegrationPoints(const ElementType & type, const GhostType & ghost_type = _not_ghost) const = 0; #endif /* ------------------------------------------------------------------------ */ /* Shape method bridges */ /* ------------------------------------------------------------------------ */ /// Compute the gradient nablauq on the integration points of an element type /// from nodal values u virtual void gradientOnIntegrationPoints( const Array<Real> & u, Array<Real> & nablauq, const UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// Interpolate a nodal field u at the integration points of an element type /// -> uq virtual void interpolateOnIntegrationPoints( const Array<Real> & u, Array<Real> & uq, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// Interpolate a nodal field u at the integration points of many element /// types -> uq virtual void interpolateOnIntegrationPoints( const Array<Real> & u, ElementTypeMapArray<Real> & uq, const ElementTypeMapArray<UInt> * filter_elements = nullptr) const = 0; /// pre multiplies a tensor by the shapes derivaties virtual void computeBtD(const Array<Real> & Ds, Array<Real> & BtDs, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const = 0; /// left and right multiplies a tensor by the shapes derivaties virtual void computeBtDB(const Array<Real> & Ds, Array<Real> & BtDBs, UInt order_d, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const = 0; /// Compute the interpolation point position in the global coordinates for /// many element types virtual void computeIntegrationPointsCoordinates( ElementTypeMapArray<Real> & integration_points_coordinates, const ElementTypeMapArray<UInt> * filter_elements = nullptr) const = 0; /// Compute the interpolation point position in the global coordinates for an /// element type virtual void computeIntegrationPointsCoordinates( Array<Real> & integration_points_coordinates, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// Build pre-computed matrices for interpolation of field form integration /// points at other given positions (interpolation_points) virtual void initElementalFieldInterpolationFromIntegrationPoints( const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, ElementTypeMapArray<Real> & integration_points_coordinates_inv_matrices, const ElementTypeMapArray<UInt> * element_filter) const = 0; /// interpolate field at given position (interpolation_points) from given /// values of this field at integration points (field) virtual void interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & result, const GhostType ghost_type, const ElementTypeMapArray<UInt> * element_filter) const = 0; /// Interpolate field at given position from given values of this field at /// integration points (field) /// using matrices precomputed with /// initElementalFieldInterplationFromIntegrationPoints virtual void interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, const ElementTypeMapArray<Real> & integration_points_coordinates_inv_matrices, ElementTypeMapArray<Real> & result, const GhostType ghost_type, const ElementTypeMapArray<UInt> * element_filter) const = 0; /// interpolate on a phyiscal point inside an element virtual void interpolate(const Vector<Real> & real_coords, const Matrix<Real> & nodal_values, Vector<Real> & interpolated, const Element & element) const = 0; /// compute the shape on a provided point virtual void computeShapes(const Vector<Real> & real_coords, UInt elem, const ElementType & type, Vector<Real> & shapes, const GhostType & ghost_type = _not_ghost) const = 0; /// compute the shape derivatives on a provided point virtual void computeShapeDerivatives(const Vector<Real> & real__coords, UInt element, const ElementType & type, Matrix<Real> & shape_derivatives, const GhostType & ghost_type = _not_ghost) const = 0; /* ------------------------------------------------------------------------ */ /* Other methods */ /* ------------------------------------------------------------------------ */ /// pre-compute normals on integration points virtual void computeNormalsOnIntegrationPoints( const GhostType & ghost_type = _not_ghost) = 0; /// pre-compute normals on integration points virtual void computeNormalsOnIntegrationPoints( __attribute__((unused)) const Array<Real> & field, __attribute__((unused)) const GhostType & ghost_type = _not_ghost) { AKANTU_TO_IMPLEMENT(); } /// pre-compute normals on integration points virtual void computeNormalsOnIntegrationPoints( __attribute__((unused)) const Array<Real> & field, __attribute__((unused)) Array<Real> & normal, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type = _not_ghost) const { AKANTU_TO_IMPLEMENT(); } #ifdef AKANTU_STRUCTURAL_MECHANICS /// assemble a field as a matrix for structural elements (ex. rho to mass /// matrix) virtual void assembleFieldMatrix( __attribute__((unused)) const Array<Real> & field_1, __attribute__((unused)) UInt nb_degree_of_freedom, __attribute__((unused)) SparseMatrix & M, __attribute__((unused)) Array<Real> * n, __attribute__((unused)) ElementTypeMapArray<Real> & rotation_mat, __attribute__((unused)) ElementType type, __attribute__((unused)) const GhostType & ghost_type) const { AKANTU_TO_IMPLEMENT(); } /// compute shapes function in a matrix for structural elements virtual void computeShapesMatrix( __attribute__((unused)) const ElementType & type, __attribute__((unused)) UInt nb_degree_of_freedom, __attribute__((unused)) UInt nb_nodes_per_element, __attribute__((unused)) Array<Real> * n, __attribute__((unused)) UInt id, __attribute__((unused)) UInt degree_to_interpolate, __attribute__((unused)) UInt degree_interpolated, __attribute__((unused)) const bool sign, __attribute__((unused)) const GhostType & ghost_type) const { AKANTU_TO_IMPLEMENT(); } #endif /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; private: /// initialise the class void init(); /* ------------------------------------------------------------------------ */ /* Mesh Event Handler interface */ /* ------------------------------------------------------------------------ */ public: void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) final {} void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, const RemovedNodesEvent &) final {} void onElementsAdded(const Array<Element> &, const NewElementsEvent &) override{}; void onElementsRemoved(const Array<Element> &, const ElementTypeMapArray<UInt> &, const RemovedElementsEvent &) override {} void onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) override {} /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: using ElementTypesIteratorHelper = ElementTypeMapArray<Real, ElementType>::ElementTypesIteratorHelper; ElementTypesIteratorHelper elementTypes(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const; /// get the dimension of the element handeled by this fe_engine object AKANTU_GET_MACRO(ElementDimension, element_dimension, UInt); /// get the mesh contained in the fem object AKANTU_GET_MACRO(Mesh, mesh, const Mesh &); /// get the mesh contained in the fem object AKANTU_GET_MACRO_NOT_CONST(Mesh, mesh, Mesh &); /// get the in-radius of an element static inline Real getElementInradius(const Matrix<Real> & coord, const ElementType & type); /// get the normals on integration points AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(NormalsOnIntegrationPoints, normals_on_integration_points, Real); /// get cohesive element type for a given facet type static inline ElementType getCohesiveElementType(const ElementType & type_facet); /// get igfem element type for a given regular type static inline Vector<ElementType> getIGFEMElementTypes(const ElementType & type); /// get the interpolation element associated to an element type static inline InterpolationType getInterpolationType(const ElementType & el_type); /// get the shape function class (probably useless: see getShapeFunction in /// fe_engine_template.hh) virtual const ShapeFunctions & getShapeFunctionsInterface() const = 0; /// get the integrator class (probably useless: see getIntegrator in /// fe_engine_template.hh) virtual const Integrator & getIntegratorInterface() const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// spatial dimension of the problem UInt element_dimension; /// the mesh on which all computation are made Mesh & mesh; /// normals at integration points ElementTypeMapArray<Real> normals_on_integration_points; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const FEEngine & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "fe_engine_inline_impl.cc" #include "fe_engine_template.hh" #endif /* __AKANTU_FE_ENGINE_HH__ */ diff --git a/src/fe_engine/fe_engine_inline_impl.cc b/src/fe_engine/fe_engine_inline_impl.cc index 48940bdb0..a04ec296e 100644 --- a/src/fe_engine/fe_engine_inline_impl.cc +++ b/src/fe_engine/fe_engine_inline_impl.cc @@ -1,199 +1,199 @@ /** * @file fe_engine_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 20 2010 - * @date last modification: Sat Sep 05 2015 + * @date last modification: Sun Aug 13 2017 * * @brief Implementation of the inline functions of the FEEngine 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "element_class.hh" #include "fe_engine.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include "element_type_conversion.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FE_ENGINE_INLINE_IMPL_CC__ #define __AKANTU_FE_ENGINE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline Real FEEngine::getElementInradius(const Matrix<Real> & coord, const ElementType & type) { AKANTU_DEBUG_IN(); Real inradius = 0; #define GET_INRADIUS(type) inradius = ElementClass<type>::getInradius(coord); AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_INRADIUS); #undef GET_INRADIUS AKANTU_DEBUG_OUT(); return inradius; } /* -------------------------------------------------------------------------- */ inline InterpolationType FEEngine::getInterpolationType(const ElementType & type) { return convertType<ElementType, InterpolationType>(type); } /* -------------------------------------------------------------------------- */ /// @todo rewrite this function in order to get the cohesive element /// type directly from the facet #if defined(AKANTU_COHESIVE_ELEMENT) inline ElementType FEEngine::getCohesiveElementType(const ElementType & type) { AKANTU_DEBUG_IN(); ElementType ctype; #define GET_COHESIVE_TYPE(type) \ ctype = CohesiveFacetProperty<type>::cohesive_type; AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_COHESIVE_TYPE); #undef GET_COHESIVE_TYPE AKANTU_DEBUG_OUT(); return ctype; } #else inline ElementType FEEngine::getCohesiveElementType(__attribute__((unused)) const ElementType & type_facet) { return _not_defined; } #endif /* -------------------------------------------------------------------------- */ #if defined(AKANTU_IGFEM) } // akantu #include "igfem_helper.hh" namespace akantu { inline Vector<ElementType> FEEngine::getIGFEMElementTypes(const ElementType & type) { #define GET_IGFEM_ELEMENT_TYPES(type) \ return IGFEMHelper::getIGFEMElementTypes<type>(); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_IGFEM_ELEMENT_TYPES); #undef GET_IGFEM_ELEMENT_TYPES } #endif /* -------------------------------------------------------------------------- */ template <typename T> void FEEngine::extractNodalToElementField(const Mesh & mesh, const Array<T> & nodal_f, Array<T> & elemental_f, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = nodal_f.getNbComponent(); UInt nb_element = mesh.getNbElement(type, ghost_type); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } elemental_f.resize(nb_element); T * nodal_f_val = nodal_f.storage(); T * f_val = elemental_f.storage(); UInt * el_conn; for (UInt el = 0; el < nb_element; ++el) { if (filter_elements != empty_filter) el_conn = conn_val + filter_elements(el) * nb_nodes_per_element; else el_conn = conn_val + el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = *(el_conn + n); std::copy(nodal_f_val + node * nb_degree_of_freedom, nodal_f_val + (node + 1) * nb_degree_of_freedom, f_val); f_val += nb_degree_of_freedom; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void FEEngine::filterElementalData(const Mesh & mesh, const Array<T> & elem_f, Array<T> & filtered_f, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_element = mesh.getNbElement(type, ghost_type); if (nb_element == 0) { filtered_f.resize(0); return; } UInt nb_degree_of_freedom = elem_f.getNbComponent(); UInt nb_data_per_element = elem_f.size() / nb_element; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } filtered_f.resize(nb_element * nb_data_per_element); T * elem_f_val = elem_f.storage(); T * f_val = filtered_f.storage(); UInt el_offset; for (UInt el = 0; el < nb_element; ++el) { if (filter_elements != empty_filter) el_offset = filter_elements(el); else el_offset = el; std::copy(elem_f_val + el_offset * nb_data_per_element * nb_degree_of_freedom, elem_f_val + (el_offset + 1) * nb_data_per_element * nb_degree_of_freedom, f_val); f_val += nb_degree_of_freedom * nb_data_per_element; } AKANTU_DEBUG_OUT(); } } // akantu #endif /* __AKANTU_FE_ENGINE_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/fe_engine_template.hh b/src/fe_engine/fe_engine_template.hh index 14e5793b6..4325dbce6 100644 --- a/src/fe_engine/fe_engine_template.hh +++ b/src/fe_engine/fe_engine_template.hh @@ -1,407 +1,407 @@ /** * @file fe_engine_template.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Mon Jan 29 2018 * * @brief templated class that calls integration and shape objects * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FE_ENGINE_TEMPLATE_HH__ #define __AKANTU_FE_ENGINE_TEMPLATE_HH__ /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "integrator.hh" #include "shape_functions.hh" /* -------------------------------------------------------------------------- */ #include <type_traits> /* -------------------------------------------------------------------------- */ namespace akantu { class DOFManager; namespace fe_engine { namespace details { template <ElementKind> struct AssembleLumpedTemplateHelper; template <ElementKind> struct AssembleFieldMatrixHelper; } // namespace details } // namespace fe_engine template <ElementKind, typename> struct AssembleFieldMatrixStructHelper; struct DefaultIntegrationOrderFunctor { template <ElementType type> static inline constexpr int getOrder() { return ElementClassProperty<type>::polynomial_degree; } }; /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind = _ek_regular, class IntegrationOrderFunctor = DefaultIntegrationOrderFunctor> class FEEngineTemplate : public FEEngine { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using Integ = I<kind, IntegrationOrderFunctor>; using Shape = S<kind>; FEEngineTemplate(Mesh & mesh, UInt spatial_dimension = _all_dimensions, ID id = "fem", MemoryID memory_id = 0); ~FEEngineTemplate() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// pre-compute all the shape functions, their derivatives and the jacobians void initShapeFunctions(const GhostType & ghost_type = _not_ghost) override; void initShapeFunctions(const Array<Real> & nodes, const GhostType & ghost_type = _not_ghost); /* ------------------------------------------------------------------------ */ /* Integration method bridges */ /* ------------------------------------------------------------------------ */ /// integrate f for all elements of type "type" void integrate(const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const override; /// integrate a scalar value on all elements of type "type" Real integrate(const Array<Real> & f, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const override; /// integrate one element scalar value on all elements of type "type" Real integrate(const Vector<Real> & f, const ElementType & type, UInt index, const GhostType & ghost_type = _not_ghost) const override; /// integrate partially around an integration point (@f$ intf_q = f_q * J_q * /// w_q @f$) void integrateOnIntegrationPoints( const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const override; /// interpolate on a phyiscal point inside an element void interpolate(const Vector<Real> & real_coords, const Matrix<Real> & nodal_values, Vector<Real> & interpolated, const Element & element) const override; /// get the number of integration points UInt getNbIntegrationPoints( const ElementType & type, const GhostType & ghost_type = _not_ghost) const override; /// get shapes precomputed const Array<Real> & getShapes(const ElementType & type, const GhostType & ghost_type = _not_ghost, UInt id = 0) const override; /// get the derivatives of shapes const Array<Real> & getShapesDerivatives(const ElementType & type, const GhostType & ghost_type = _not_ghost, UInt id = 0) const override; /// get integration points const inline Matrix<Real> & getIntegrationPoints( const ElementType & type, const GhostType & ghost_type = _not_ghost) const override; /* ------------------------------------------------------------------------ */ /* Shape method bridges */ /* ------------------------------------------------------------------------ */ /// compute the gradient of a nodal field on the integration points void gradientOnIntegrationPoints( const Array<Real> & u, Array<Real> & nablauq, const UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const override; /// interpolate a nodal field on the integration points void interpolateOnIntegrationPoints( const Array<Real> & u, Array<Real> & uq, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const override; /// interpolate a nodal field on the integration points given a /// by_element_type void interpolateOnIntegrationPoints( const Array<Real> & u, ElementTypeMapArray<Real> & uq, const ElementTypeMapArray<UInt> * filter_elements = nullptr) const override; /// pre multiplies a tensor by the shapes derivaties void computeBtD(const Array<Real> & Ds, Array<Real> & BtDs, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const override; /// left and right multiplies a tensor by the shapes derivaties void computeBtDB( const Array<Real> & Ds, Array<Real> & BtDBs, UInt order_d, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const override; /// compute the position of integration points given by an element_type_map /// from nodes position inline void computeIntegrationPointsCoordinates( ElementTypeMapArray<Real> & quadrature_points_coordinates, const ElementTypeMapArray<UInt> * filter_elements = nullptr) const override; /// compute the position of integration points from nodes position inline void computeIntegrationPointsCoordinates( Array<Real> & quadrature_points_coordinates, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const override; /// interpolate field at given position (interpolation_points) from given /// values of this field at integration points (field) inline void interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & result, const GhostType ghost_type, const ElementTypeMapArray<UInt> * element_filter) const override; /// Interpolate field at given position from given values of this field at /// integration points (field) /// using matrices precomputed with /// initElementalFieldInterplationFromIntegrationPoints inline void interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, const ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, ElementTypeMapArray<Real> & result, const GhostType ghost_type, const ElementTypeMapArray<UInt> * element_filter) const override; /// Build pre-computed matrices for interpolation of field form integration /// points at other given positions (interpolation_points) inline void initElementalFieldInterpolationFromIntegrationPoints( const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, const ElementTypeMapArray<UInt> * element_filter = nullptr) const override; /// find natural coords from real coords provided an element void inverseMap(const Vector<Real> & real_coords, UInt element, const ElementType & type, Vector<Real> & natural_coords, const GhostType & ghost_type = _not_ghost) const; /// return true if the coordinates provided are inside the element, false /// otherwise inline bool contains(const Vector<Real> & real_coords, UInt element, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /// compute the shape on a provided point inline void computeShapes(const Vector<Real> & real_coords, UInt element, const ElementType & type, Vector<Real> & shapes, const GhostType & ghost_type = _not_ghost) const override; /// compute the shape derivatives on a provided point inline void computeShapeDerivatives( const Vector<Real> & real__coords, UInt element, const ElementType & type, Matrix<Real> & shape_derivatives, const GhostType & ghost_type = _not_ghost) const override; /* ------------------------------------------------------------------------ */ /* Other methods */ /* ------------------------------------------------------------------------ */ /// pre-compute normals on integration points void computeNormalsOnIntegrationPoints( const GhostType & ghost_type = _not_ghost) override; void computeNormalsOnIntegrationPoints( const Array<Real> & field, const GhostType & ghost_type = _not_ghost) override; void computeNormalsOnIntegrationPoints( const Array<Real> & field, Array<Real> & normal, const ElementType & type, const GhostType & ghost_type = _not_ghost) const override; template <ElementType type> void computeNormalsOnIntegrationPoints(const Array<Real> & field, Array<Real> & normal, const GhostType & ghost_type) const; private: // To avoid a weird full specialization of a method in a non specalized class void computeNormalsOnIntegrationPointsPoint1(const Array<Real> &, Array<Real> & normal, const GhostType & ghost_type) const; public: /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override; /// assemble a field as a lumped matrix (ex. rho in lumped mass) template <class Functor> void assembleFieldLumped(const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, ElementType type, const GhostType & ghost_type) const; /// assemble a field as a matrix (ex. rho to mass matrix) template <class Functor> void assembleFieldMatrix(const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, ElementType type, const GhostType & ghost_type) const; #ifdef AKANTU_STRUCTURAL_MECHANICS /// assemble a field as a matrix (ex. rho to mass matrix) void assembleFieldMatrix(const Array<Real> & field_1, UInt nb_degree_of_freedom, SparseMatrix & M, Array<Real> * n, ElementTypeMapArray<Real> & rotation_mat, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /// compute shapes function in a matrix for structural elements void computeShapesMatrix(const ElementType & type, UInt nb_degree_of_freedom, UInt nb_nodes_per_element, Array<Real> * n, UInt id, UInt degree_to_interpolate, UInt degree_interpolated, const bool sign, const GhostType & ghost_type = _not_ghost) const override; #endif private: friend struct fe_engine::details::AssembleLumpedTemplateHelper<kind>; friend struct fe_engine::details::AssembleFieldMatrixHelper<kind>; friend struct AssembleFieldMatrixStructHelper<kind, void>; /// templated function to compute the scaling to assemble a lumped matrix template <class Functor, ElementType type> void assembleFieldLumped(const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const; /// @f$ \tilde{M}_{i} = \sum_j M_{ij} = \sum_j \int \rho \varphi_i \varphi_j /// dV = \int \rho \varphi_i dV @f$ template <ElementType type> void assembleLumpedRowSum(const Array<Real> & field, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const; /// @f$ \tilde{M}_{i} = c * M_{ii} = \int_{V_e} \rho dV @f$ template <ElementType type> void assembleLumpedDiagonalScaling(const Array<Real> & field, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const; /// assemble a field as a matrix (ex. rho to mass matrix) template <class Functor, ElementType type> void assembleFieldMatrix(const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const; #ifdef AKANTU_STRUCTURAL_MECHANICS /// assemble a field as a matrix for structural elements (ex. rho to mass /// matrix) template <ElementType type> void assembleFieldMatrix(const Array<Real> & field_1, UInt nb_degree_of_freedom, SparseMatrix & M, Array<Real> * n, ElementTypeMapArray<Real> & rotation_mat, __attribute__((unused)) const GhostType & ghost_type) const; #endif /* ------------------------------------------------------------------------ */ /* Mesh Event Handler interface */ /* ------------------------------------------------------------------------ */ public: void onElementsAdded(const Array<Element> &, const NewElementsEvent &) override; void onElementsRemoved(const Array<Element> &, const ElementTypeMapArray<UInt> &, const RemovedElementsEvent &) override; void onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the shape class (probably useless: see getShapeFunction) const ShapeFunctions & getShapeFunctionsInterface() const override { return shape_functions; }; /// get the shape class const Shape & getShapeFunctions() const { return shape_functions; }; /// get the integrator class (probably useless: see getIntegrator) const Integrator & getIntegratorInterface() const override { return integrator; }; /// get the integrator class const Integ & getIntegrator() const { return integrator; }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: Integ integrator; Shape shape_functions; }; } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "fe_engine_template_tmpl.hh" #include "fe_engine_template_tmpl_field.hh" /* -------------------------------------------------------------------------- */ /* Shape Linked specialization */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_STRUCTURAL_MECHANICS) #include "fe_engine_template_tmpl_struct.hh" #endif /* -------------------------------------------------------------------------- */ /* Shape IGFEM specialization */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_IGFEM) #include "fe_engine_template_tmpl_igfem.hh" #endif #endif /* __AKANTU_FE_ENGINE_TEMPLATE_HH__ */ diff --git a/src/fe_engine/fe_engine_template_cohesive.cc b/src/fe_engine/fe_engine_template_cohesive.cc index d93f779f0..447463fc4 100644 --- a/src/fe_engine/fe_engine_template_cohesive.cc +++ b/src/fe_engine/fe_engine_template_cohesive.cc @@ -1,133 +1,132 @@ /** * @file fe_engine_template_cohesive.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Oct 31 2012 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Specialization of the FEEngineTemplate for cohesive element * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fe_engine_template.hh" #include "integrator_gauss.hh" #include "shape_cohesive.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* compatibility functions */ /* -------------------------------------------------------------------------- */ template <> Real FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive, DefaultIntegrationOrderFunctor>:: integrate(const Array<Real> & f, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); #ifndef AKANTU_NDEBUG UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements != empty_filter) nb_element = filter_elements.size(); UInt nb_quadrature_points = getNbIntegrationPoints(type); AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << ") has not the good size."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == 1, "The vector f(" << f.getID() << ") has not the good number of component."); #endif Real integral = 0.; #define INTEGRATE(type) \ integral = integrator.integrate<type>(f, ghost_type, filter_elements); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE AKANTU_DEBUG_OUT(); return integral; } /* -------------------------------------------------------------------------- */ template <> void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive, DefaultIntegrationOrderFunctor>:: integrate(const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { #ifndef AKANTU_NDEBUG UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements == filter_elements) nb_element = filter_elements.size(); UInt nb_quadrature_points = getNbIntegrationPoints(type); AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << " size " << f.size() << ") has not the good size (" << nb_element << ")."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom, "The vector f(" << f.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom, "The vector intf(" << intf.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.size() == nb_element, "The vector intf(" << intf.getID() << ") has not the good size."); #endif #define INTEGRATE(type) \ integrator.integrate<type>(f, intf, nb_degree_of_freedom, ghost_type, \ filter_elements); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE } /* -------------------------------------------------------------------------- */ template <> void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive, DefaultIntegrationOrderFunctor>:: gradientOnIntegrationPoints(const Array<Real> &, Array<Real> &, const UInt, const ElementType &, const GhostType &, const Array<UInt> &) const { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/fe_engine/fe_engine_template_tmpl.hh b/src/fe_engine/fe_engine_template_tmpl.hh index 1d5c54b00..bace4d338 100644 --- a/src/fe_engine/fe_engine_template_tmpl.hh +++ b/src/fe_engine/fe_engine_template_tmpl.hh @@ -1,1374 +1,1373 @@ /** * @file fe_engine_template_tmpl.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Feb 15 2011 - * @date last modification: Thu Nov 19 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Template implementation of FEEngineTemplate * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dof_manager.hh" #include "fe_engine_template.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::FEEngineTemplate( Mesh & mesh, UInt spatial_dimension, ID id, MemoryID memory_id) : FEEngine(mesh, spatial_dimension, id, memory_id), integrator(mesh, id, memory_id), shape_functions(mesh, id, memory_id) {} /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::~FEEngineTemplate() = default; /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct GradientOnIntegrationPointsHelper { template <class S> static void call(const S &, Mesh &, const Array<Real> &, Array<Real> &, const UInt, const ElementType &, const GhostType &, const Array<UInt> &) { AKANTU_TO_IMPLEMENT(); } }; #define COMPUTE_GRADIENT(type) \ if (element_dimension == ElementClass<type>::getSpatialDimension()) \ shape_functions.template gradientOnIntegrationPoints<type>( \ u, nablauq, nb_degree_of_freedom, ghost_type, filter_elements); #define AKANTU_SPECIALIZE_GRADIENT_ON_INTEGRATION_POINTS_HELPER(kind) \ template <> struct GradientOnIntegrationPointsHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, Mesh & mesh, \ const Array<Real> & u, Array<Real> & nablauq, \ const UInt nb_degree_of_freedom, \ const ElementType & type, const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ UInt element_dimension = mesh.getSpatialDimension(type); \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(COMPUTE_GRADIENT, kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST( AKANTU_SPECIALIZE_GRADIENT_ON_INTEGRATION_POINTS_HELPER, AKANTU_FE_ENGINE_LIST_GRADIENT_ON_INTEGRATION_POINTS) #undef AKANTU_SPECIALIZE_GRADIENT_ON_INTEGRATION_POINTS_HELPER #undef COMPUTE_GRADIENT } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: gradientOnIntegrationPoints(const Array<Real> & u, Array<Real> & nablauq, const UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements != empty_filter) nb_element = filter_elements.size(); UInt nb_points = shape_functions.getIntegrationPoints(type, ghost_type).cols(); #ifndef AKANTU_NDEBUG UInt element_dimension = mesh.getSpatialDimension(type); AKANTU_DEBUG_ASSERT(u.size() == mesh.getNbNodes(), "The vector u(" << u.getID() << ") has not the good size."); AKANTU_DEBUG_ASSERT(u.getNbComponent() == nb_degree_of_freedom, "The vector u(" << u.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT( nablauq.getNbComponent() == nb_degree_of_freedom * element_dimension, "The vector nablauq(" << nablauq.getID() << ") has not the good number of component."); // AKANTU_DEBUG_ASSERT(nablauq.size() == nb_element * nb_points, // "The vector nablauq(" << nablauq.getID() // << ") has not the good size."); #endif nablauq.resize(nb_element * nb_points); fe_engine::details::GradientOnIntegrationPointsHelper<kind>::call( shape_functions, mesh, u, nablauq, nb_degree_of_freedom, type, ghost_type, filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::initShapeFunctions( const GhostType & ghost_type) { initShapeFunctions(mesh.getNodes(), ghost_type); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::initShapeFunctions( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); for (auto & type : mesh.elementTypes(element_dimension, ghost_type, kind)) { integrator.initIntegrator(nodes, type, ghost_type); const auto & control_points = getIntegrationPoints(type, ghost_type); shape_functions.initShapeFunctions(nodes, control_points, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct IntegrateHelper {}; #define INTEGRATE(type) \ integrator.template integrate<type>(f, intf, nb_degree_of_freedom, \ ghost_type, filter_elements); #define AKANTU_SPECIALIZE_INTEGRATE_HELPER(kind) \ template <> struct IntegrateHelper<kind> { \ template <class I> \ static void call(const I & integrator, const Array<Real> & f, \ Array<Real> & intf, UInt nb_degree_of_freedom, \ const ElementType & type, const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INTEGRATE, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_INTEGRATE_HELPER) #undef AKANTU_SPECIALIZE_INTEGRATE_HELPER #undef INTEGRATE } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::integrate( const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements != empty_filter) nb_element = filter_elements.size(); #ifndef AKANTU_NDEBUG UInt nb_quadrature_points = getNbIntegrationPoints(type); AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << " size " << f.size() << ") has not the good size (" << nb_element << ")."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom, "The vector f(" << f.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom, "The vector intf(" << intf.getID() << ") has not the good number of component."); #endif intf.resize(nb_element); fe_engine::details::IntegrateHelper<kind>::call(integrator, f, intf, nb_degree_of_freedom, type, ghost_type, filter_elements); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct IntegrateScalarHelper {}; #define INTEGRATE(type) \ integral = \ integrator.template integrate<type>(f, ghost_type, filter_elements); #define AKANTU_SPECIALIZE_INTEGRATE_SCALAR_HELPER(kind) \ template <> struct IntegrateScalarHelper<kind> { \ template <class I> \ static Real call(const I & integrator, const Array<Real> & f, \ const ElementType & type, const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ Real integral = 0.; \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INTEGRATE, kind); \ return integral; \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_INTEGRATE_SCALAR_HELPER) #undef AKANTU_SPECIALIZE_INTEGRATE_SCALAR_HELPER #undef INTEGRATE } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> Real FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::integrate( const Array<Real> & f, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); #ifndef AKANTU_NDEBUG // std::stringstream sstr; sstr << ghost_type; // AKANTU_DEBUG_ASSERT(sstr.str() == nablauq.getTag(), // "The vector " << nablauq.getID() << " is not taged " << // ghost_type); UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements != empty_filter) nb_element = filter_elements.size(); UInt nb_quadrature_points = getNbIntegrationPoints(type, ghost_type); AKANTU_DEBUG_ASSERT( f.size() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << ") has not the good size. (" << f.size() << "!=" << nb_quadrature_points * nb_element << ")"); AKANTU_DEBUG_ASSERT(f.getNbComponent() == 1, "The vector f(" << f.getID() << ") has not the good number of component."); #endif Real integral = fe_engine::details::IntegrateScalarHelper<kind>::call( integrator, f, type, ghost_type, filter_elements); AKANTU_DEBUG_OUT(); return integral; } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct IntegrateScalarOnOneElementHelper {}; #define INTEGRATE(type) \ res = integrator.template integrate<type>(f, index, ghost_type); #define AKANTU_SPECIALIZE_INTEGRATE_SCALAR_ON_ONE_ELEMENT_HELPER(kind) \ template <> struct IntegrateScalarOnOneElementHelper<kind> { \ template <class I> \ static Real call(const I & integrator, const Vector<Real> & f, \ const ElementType & type, UInt index, \ const GhostType & ghost_type) { \ Real res = 0.; \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INTEGRATE, kind); \ return res; \ } \ }; AKANTU_BOOST_ALL_KIND( AKANTU_SPECIALIZE_INTEGRATE_SCALAR_ON_ONE_ELEMENT_HELPER) #undef AKANTU_SPECIALIZE_INTEGRATE_SCALAR_ON_ONE_ELEMENT_HELPER #undef INTEGRATE } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> Real FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::integrate( const Vector<Real> & f, const ElementType & type, UInt index, const GhostType & ghost_type) const { Real res = fe_engine::details::IntegrateScalarOnOneElementHelper<kind>::call( integrator, f, type, index, ghost_type); return res; } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct IntegrateOnIntegrationPointsHelper {}; #define INTEGRATE(type) \ integrator.template integrateOnIntegrationPoints<type>( \ f, intf, nb_degree_of_freedom, ghost_type, filter_elements); #define AKANTU_SPECIALIZE_INTEGRATE_ON_INTEGRATION_POINTS_HELPER(kind) \ template <> struct IntegrateOnIntegrationPointsHelper<kind> { \ template <class I> \ static void call(const I & integrator, const Array<Real> & f, \ Array<Real> & intf, UInt nb_degree_of_freedom, \ const ElementType & type, const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INTEGRATE, kind); \ } \ }; AKANTU_BOOST_ALL_KIND( AKANTU_SPECIALIZE_INTEGRATE_ON_INTEGRATION_POINTS_HELPER) #undef AKANTU_SPECIALIZE_INTEGRATE_ON_INTEGRATION_POINTS_HELPER #undef INTEGRATE } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: integrateOnIntegrationPoints(const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements != empty_filter) nb_element = filter_elements.size(); UInt nb_quadrature_points = getNbIntegrationPoints(type); #ifndef AKANTU_NDEBUG // std::stringstream sstr; sstr << ghost_type; // AKANTU_DEBUG_ASSERT(sstr.str() == nablauq.getTag(), // "The vector " << nablauq.getID() << " is not taged " << // ghost_type); AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << " size " << f.size() << ") has not the good size (" << nb_element << ")."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom, "The vector f(" << f.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom, "The vector intf(" << intf.getID() << ") has not the good number of component."); #endif intf.resize(nb_element * nb_quadrature_points); fe_engine::details::IntegrateOnIntegrationPointsHelper<kind>::call( integrator, f, intf, nb_degree_of_freedom, type, ghost_type, filter_elements); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct InterpolateOnIntegrationPointsHelper { template <class S> static void call(const S &, const Array<Real> &, Array<Real> &, const UInt, const ElementType &, const GhostType &, const Array<UInt> &) { AKANTU_TO_IMPLEMENT(); } }; #define INTERPOLATE(type) \ shape_functions.template interpolateOnIntegrationPoints<type>( \ u, uq, nb_degree_of_freedom, ghost_type, filter_elements); #define AKANTU_SPECIALIZE_INTERPOLATE_ON_INTEGRATION_POINTS_HELPER(kind) \ template <> struct InterpolateOnIntegrationPointsHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, const Array<Real> & u, \ Array<Real> & uq, const UInt nb_degree_of_freedom, \ const ElementType & type, const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INTERPOLATE, kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST( AKANTU_SPECIALIZE_INTERPOLATE_ON_INTEGRATION_POINTS_HELPER, AKANTU_FE_ENGINE_LIST_INTERPOLATE_ON_INTEGRATION_POINTS) #undef AKANTU_SPECIALIZE_INTERPOLATE_ON_INTEGRATION_POINTS_HELPER #undef INTERPOLATE } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: interpolateOnIntegrationPoints(const Array<Real> & u, Array<Real> & uq, const UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_points = shape_functions.getIntegrationPoints(type, ghost_type).cols(); UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements != empty_filter) nb_element = filter_elements.size(); #ifndef AKANTU_NDEBUG AKANTU_DEBUG_ASSERT(u.size() == mesh.getNbNodes(), "The vector u(" << u.getID() << ") has not the good size."); AKANTU_DEBUG_ASSERT(u.getNbComponent() == nb_degree_of_freedom, "The vector u(" << u.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(uq.getNbComponent() == nb_degree_of_freedom, "The vector uq(" << uq.getID() << ") has not the good number of component."); #endif uq.resize(nb_element * nb_points); fe_engine::details::InterpolateOnIntegrationPointsHelper<kind>::call( shape_functions, u, uq, nb_degree_of_freedom, type, ghost_type, filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: interpolateOnIntegrationPoints( const Array<Real> & u, ElementTypeMapArray<Real> & uq, const ElementTypeMapArray<UInt> * filter_elements) const { AKANTU_DEBUG_IN(); const Array<UInt> * filter = nullptr; for (auto ghost_type : ghost_types) { for (auto & type : uq.elementTypes(_all_dimensions, ghost_type, kind)) { UInt nb_quad_per_element = getNbIntegrationPoints(type, ghost_type); UInt nb_element = 0; if (filter_elements) { filter = &((*filter_elements)(type, ghost_type)); nb_element = filter->size(); } else { filter = &empty_filter; nb_element = mesh.getNbElement(type, ghost_type); } UInt nb_tot_quad = nb_quad_per_element * nb_element; Array<Real> & quad = uq(type, ghost_type); quad.resize(nb_tot_quad); interpolateOnIntegrationPoints(u, quad, quad.getNbComponent(), type, ghost_type, *filter); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ namespace fe_engine { namespace details { template <ElementKind kind> struct ComputeBtDHelper {}; #define COMPUTE_BTD(type) \ shape_functions.template computeBtD<type>(Ds, BtDs, ghost_type, \ filter_elements); #define AKANTU_SPECIALIZE_COMPUTE_BtD_HELPER(kind) \ template <> struct ComputeBtDHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, const Array<Real> & Ds, \ Array<Real> & BtDs, const ElementType & type, \ const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(COMPUTE_BTD, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_COMPUTE_BtD_HELPER) #undef AKANTU_SPECIALIZE_COMPUTE_BtD_HELPER #undef COMPUTE_BTD } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::computeBtD( const Array<Real> & Ds, Array<Real> & BtDs, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { fe_engine::details::ComputeBtDHelper<kind>::call( shape_functions, Ds, BtDs, type, ghost_type, filter_elements); } /* -------------------------------------------------------------------------- */ namespace fe_engine { namespace details { template <ElementKind kind> struct ComputeBtDBHelper {}; #define COMPUTE_BTDB(type) \ shape_functions.template computeBtDB<type>(Ds, BtDBs, order_d, ghost_type, \ filter_elements); #define AKANTU_SPECIALIZE_COMPUTE_BtDB_HELPER(kind) \ template <> struct ComputeBtDBHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, const Array<Real> & Ds, \ Array<Real> & BtDBs, UInt order_d, \ const ElementType & type, const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(COMPUTE_BTDB, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_COMPUTE_BtDB_HELPER) #undef AKANTU_SPECIALIZE_COMPUTE_BtDB_HELPER #undef COMPUTE_BTDB } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::computeBtDB( const Array<Real> & Ds, Array<Real> & BtDBs, UInt order_d, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { fe_engine::details::ComputeBtDBHelper<kind>::call( shape_functions, Ds, BtDBs, order_d, type, ghost_type, filter_elements); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: computeIntegrationPointsCoordinates( ElementTypeMapArray<Real> & quadrature_points_coordinates, const ElementTypeMapArray<UInt> * filter_elements) const { const Array<Real> & nodes_coordinates = mesh.getNodes(); interpolateOnIntegrationPoints( nodes_coordinates, quadrature_points_coordinates, filter_elements); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: computeIntegrationPointsCoordinates( Array<Real> & quadrature_points_coordinates, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { const Array<Real> & nodes_coordinates = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); interpolateOnIntegrationPoints( nodes_coordinates, quadrature_points_coordinates, spatial_dimension, type, ghost_type, filter_elements); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: initElementalFieldInterpolationFromIntegrationPoints( const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, const ElementTypeMapArray<UInt> * element_filter) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = this->mesh.getSpatialDimension(); ElementTypeMapArray<Real> quadrature_points_coordinates( "quadrature_points_coordinates_for_interpolation", getID(), getMemoryID()); quadrature_points_coordinates.initialize(*this, _nb_component = spatial_dimension); computeIntegrationPointsCoordinates(quadrature_points_coordinates, element_filter); shape_functions.initElementalFieldInterpolationFromIntegrationPoints( interpolation_points_coordinates, interpolation_points_coordinates_matrices, quad_points_coordinates_inv_matrices, quadrature_points_coordinates, element_filter); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & result, const GhostType ghost_type, const ElementTypeMapArray<UInt> * element_filter) const { ElementTypeMapArray<Real> interpolation_points_coordinates_matrices( "interpolation_points_coordinates_matrices", id, memory_id); ElementTypeMapArray<Real> quad_points_coordinates_inv_matrices( "quad_points_coordinates_inv_matrices", id, memory_id); initElementalFieldInterpolationFromIntegrationPoints( interpolation_points_coordinates, interpolation_points_coordinates_matrices, quad_points_coordinates_inv_matrices, element_filter); interpolateElementalFieldFromIntegrationPoints( field, interpolation_points_coordinates_matrices, quad_points_coordinates_inv_matrices, result, ghost_type, element_filter); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, const ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, ElementTypeMapArray<Real> & result, const GhostType ghost_type, const ElementTypeMapArray<UInt> * element_filter) const { shape_functions.interpolateElementalFieldFromIntegrationPoints( field, interpolation_points_coordinates_matrices, quad_points_coordinates_inv_matrices, result, ghost_type, element_filter); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct InterpolateHelper { template <class S> static void call(const S &, const Vector<Real> &, UInt, const Matrix<Real> &, Vector<Real> &, const ElementType &, const GhostType &) { AKANTU_TO_IMPLEMENT(); } }; #define INTERPOLATE(type) \ shape_functions.template interpolate<type>( \ real_coords, element, nodal_values, interpolated, ghost_type); #define AKANTU_SPECIALIZE_INTERPOLATE_HELPER(kind) \ template <> struct InterpolateHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, \ const Vector<Real> & real_coords, UInt element, \ const Matrix<Real> & nodal_values, \ Vector<Real> & interpolated, const ElementType & type, \ const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INTERPOLATE, kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST(AKANTU_SPECIALIZE_INTERPOLATE_HELPER, AKANTU_FE_ENGINE_LIST_INTERPOLATE) #undef AKANTU_SPECIALIZE_INTERPOLATE_HELPER #undef INTERPOLATE } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::interpolate( const Vector<Real> & real_coords, const Matrix<Real> & nodal_values, Vector<Real> & interpolated, const Element & element) const { AKANTU_DEBUG_IN(); fe_engine::details::InterpolateHelper<kind>::call( shape_functions, real_coords, element.element, nodal_values, interpolated, element.type, element.ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: computeNormalsOnIntegrationPoints(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); computeNormalsOnIntegrationPoints(mesh.getNodes(), ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: computeNormalsOnIntegrationPoints(const Array<Real> & field, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); // Real * coord = mesh.getNodes().storage(); UInt spatial_dimension = mesh.getSpatialDimension(); // allocate the normal arrays for (auto & type : mesh.elementTypes(element_dimension, ghost_type, kind)) { UInt size = mesh.getNbElement(type, ghost_type); if (normals_on_integration_points.exists(type, ghost_type)) { normals_on_integration_points(type, ghost_type).resize(size); } else { normals_on_integration_points.alloc(size, spatial_dimension, type, ghost_type); } } // loop over the type to build the normals for (auto & type : mesh.elementTypes(element_dimension, ghost_type, kind)) { Array<Real> & normals_on_quad = normals_on_integration_points(type, ghost_type); computeNormalsOnIntegrationPoints(field, normals_on_quad, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct ComputeNormalsOnIntegrationPoints { template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind k, class IOF> static void call(const FEEngineTemplate<I, S, k, IOF> &, const Array<Real> &, Array<Real> &, const ElementType &, const GhostType &) { AKANTU_TO_IMPLEMENT(); } }; #define COMPUTE_NORMALS_ON_INTEGRATION_POINTS(type) \ fem.template computeNormalsOnIntegrationPoints<type>(field, normal, \ ghost_type); #define AKANTU_SPECIALIZE_COMPUTE_NORMALS_ON_INTEGRATION_POINTS(kind) \ template <> struct ComputeNormalsOnIntegrationPoints<kind> { \ template <template <ElementKind, class> class I, \ template <ElementKind> class S, ElementKind k, class IOF> \ static void call(const FEEngineTemplate<I, S, k, IOF> & fem, \ const Array<Real> & field, Array<Real> & normal, \ const ElementType & type, const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(COMPUTE_NORMALS_ON_INTEGRATION_POINTS, \ kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST( AKANTU_SPECIALIZE_COMPUTE_NORMALS_ON_INTEGRATION_POINTS, AKANTU_FE_ENGINE_LIST_COMPUTE_NORMALS_ON_INTEGRATION_POINTS) #undef AKANTU_SPECIALIZE_COMPUTE_NORMALS_ON_INTEGRATION_POINTS #undef COMPUTE_NORMALS_ON_INTEGRATION_POINTS } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: computeNormalsOnIntegrationPoints(const Array<Real> & field, Array<Real> & normal, const ElementType & type, const GhostType & ghost_type) const { fe_engine::details::ComputeNormalsOnIntegrationPoints<kind>::call( *this, field, normal, type, ghost_type); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: computeNormalsOnIntegrationPoints(const Array<Real> & field, Array<Real> & normal, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); if (type == _point_1) { computeNormalsOnIntegrationPointsPoint1(field, normal, ghost_type); return; } UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_points = getNbIntegrationPoints(type, ghost_type); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); normal.resize(nb_element * nb_points); Array<Real>::matrix_iterator normals_on_quad = normal.begin_reinterpret(spatial_dimension, nb_points, nb_element); Array<Real> f_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, field, f_el, type, ghost_type); const Matrix<Real> & quads = integrator.template getIntegrationPoints<type>(ghost_type); Array<Real>::matrix_iterator f_it = f_el.begin(spatial_dimension, nb_nodes_per_element); for (UInt elem = 0; elem < nb_element; ++elem) { ElementClass<type>::computeNormalsOnNaturalCoordinates(quads, *f_it, *normals_on_quad); ++normals_on_quad; ++f_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ template <ElementKind kind> struct InverseMapHelper { template <class S> static void call(const S & /*shape_functions*/, const Vector<Real> & /*real_coords*/, UInt /*element*/, const ElementType & /*type*/, Vector<Real> & /*natural_coords*/, const GhostType & /*ghost_type*/) { AKANTU_TO_IMPLEMENT(); } }; #define INVERSE_MAP(type) \ shape_functions.template inverseMap<type>(real_coords, element, \ natural_coords, ghost_type); #define AKANTU_SPECIALIZE_INVERSE_MAP_HELPER(kind) \ template <> struct InverseMapHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, \ const Vector<Real> & real_coords, UInt element, \ const ElementType & type, Vector<Real> & natural_coords, \ const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INVERSE_MAP, kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST(AKANTU_SPECIALIZE_INVERSE_MAP_HELPER, AKANTU_FE_ENGINE_LIST_INVERSE_MAP) #undef AKANTU_SPECIALIZE_INVERSE_MAP_HELPER #undef INVERSE_MAP template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::inverseMap( const Vector<Real> & real_coords, UInt element, const ElementType & type, Vector<Real> & natural_coords, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); InverseMapHelper<kind>::call(shape_functions, real_coords, element, type, natural_coords, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct ContainsHelper { template <class S> static void call(const S &, const Vector<Real> &, UInt, const ElementType &, const GhostType &) { AKANTU_TO_IMPLEMENT(); } }; #define CONTAINS(type) \ contain = shape_functions.template contains<type>(real_coords, element, \ ghost_type); #define AKANTU_SPECIALIZE_CONTAINS_HELPER(kind) \ template <> struct ContainsHelper<kind> { \ template <template <ElementKind> class S, ElementKind k> \ static bool call(const S<k> & shape_functions, \ const Vector<Real> & real_coords, UInt element, \ const ElementType & type, const GhostType & ghost_type) { \ bool contain = false; \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(CONTAINS, kind); \ return contain; \ } \ }; AKANTU_BOOST_ALL_KIND_LIST(AKANTU_SPECIALIZE_CONTAINS_HELPER, AKANTU_FE_ENGINE_LIST_CONTAINS) #undef AKANTU_SPECIALIZE_CONTAINS_HELPER #undef CONTAINS } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline bool FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::contains( const Vector<Real> & real_coords, UInt element, const ElementType & type, const GhostType & ghost_type) const { return fe_engine::details::ContainsHelper<kind>::call( shape_functions, real_coords, element, type, ghost_type); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct ComputeShapesHelper { template <class S> static void call(const S &, const Vector<Real> &, UInt, const ElementType, Vector<Real> &, const GhostType &) { AKANTU_TO_IMPLEMENT(); } }; #define COMPUTE_SHAPES(type) \ shape_functions.template computeShapes<type>(real_coords, element, shapes, \ ghost_type); #define AKANTU_SPECIALIZE_COMPUTE_SHAPES_HELPER(kind) \ template <> struct ComputeShapesHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, \ const Vector<Real> & real_coords, UInt element, \ const ElementType type, Vector<Real> & shapes, \ const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(COMPUTE_SHAPES, kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST(AKANTU_SPECIALIZE_COMPUTE_SHAPES_HELPER, AKANTU_FE_ENGINE_LIST_COMPUTE_SHAPES) #undef AKANTU_SPECIALIZE_COMPUTE_SHAPES_HELPER #undef COMPUTE_SHAPES } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::computeShapes( const Vector<Real> & real_coords, UInt element, const ElementType & type, Vector<Real> & shapes, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); fe_engine::details::ComputeShapesHelper<kind>::call( shape_functions, real_coords, element, type, shapes, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct ComputeShapeDerivativesHelper { template <class S> static void call(__attribute__((unused)) const S & shape_functions, __attribute__((unused)) const Vector<Real> & real_coords, __attribute__((unused)) UInt element, __attribute__((unused)) const ElementType type, __attribute__((unused)) Matrix<Real> & shape_derivatives, __attribute__((unused)) const GhostType & ghost_type) { AKANTU_TO_IMPLEMENT(); } }; #define COMPUTE_SHAPE_DERIVATIVES(type) \ Matrix<Real> coords_mat(real_coords.storage(), shape_derivatives.rows(), 1); \ Tensor3<Real> shapesd_tensor(shape_derivatives.storage(), \ shape_derivatives.rows(), \ shape_derivatives.cols(), 1); \ shape_functions.template computeShapeDerivatives<type>( \ coords_mat, element, shapesd_tensor, ghost_type); #define AKANTU_SPECIALIZE_COMPUTE_SHAPE_DERIVATIVES_HELPER(kind) \ template <> struct ComputeShapeDerivativesHelper<kind> { \ template <class S> \ static void call(const S & shape_functions, \ const Vector<Real> & real_coords, UInt element, \ const ElementType type, Matrix<Real> & shape_derivatives, \ const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(COMPUTE_SHAPE_DERIVATIVES, kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST( AKANTU_SPECIALIZE_COMPUTE_SHAPE_DERIVATIVES_HELPER, AKANTU_FE_ENGINE_LIST_COMPUTE_SHAPES_DERIVATIVES) #undef AKANTU_SPECIALIZE_COMPUTE_SHAPE_DERIVATIVES_HELPER #undef COMPUTE_SHAPE_DERIVATIVES } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::computeShapeDerivatives( const Vector<Real> & real_coords, UInt element, const ElementType & type, Matrix<Real> & shape_derivatives, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); fe_engine::details::ComputeShapeDerivativesHelper<kind>::call( shape_functions, real_coords, element, type, shape_derivatives, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct GetNbIntegrationPointsHelper {}; #define GET_NB_INTEGRATION_POINTS(type) \ nb_quad_points = integrator.template getNbIntegrationPoints<type>(ghost_type); #define AKANTU_SPECIALIZE_GET_NB_INTEGRATION_POINTS_HELPER(kind) \ template <> struct GetNbIntegrationPointsHelper<kind> { \ template <template <ElementKind, class> class I, ElementKind k, class IOF> \ static UInt call(const I<k, IOF> & integrator, const ElementType type, \ const GhostType & ghost_type) { \ UInt nb_quad_points = 0; \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_NB_INTEGRATION_POINTS, kind); \ return nb_quad_points; \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_GET_NB_INTEGRATION_POINTS_HELPER) #undef AKANTU_SPECIALIZE_GET_NB_INTEGRATION_POINTS_HELPER #undef GET_NB_INTEGRATION } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline UInt FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::getNbIntegrationPoints( const ElementType & type, const GhostType & ghost_type) const { return fe_engine::details::GetNbIntegrationPointsHelper<kind>::call( integrator, type, ghost_type); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct GetShapesHelper {}; #define GET_SHAPES(type) ret = &(shape_functions.getShapes(type, ghost_type)); #define AKANTU_SPECIALIZE_GET_SHAPES_HELPER(kind) \ template <> struct GetShapesHelper<kind> { \ template <class S> \ static const Array<Real> & call(const S & shape_functions, \ const ElementType type, \ const GhostType & ghost_type) { \ const Array<Real> * ret = NULL; \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_SHAPES, kind); \ return *ret; \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_GET_SHAPES_HELPER) #undef AKANTU_SPECIALIZE_GET_SHAPES_HELPER #undef GET_SHAPES } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline const Array<Real> & FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::getShapes( const ElementType & type, const GhostType & ghost_type, __attribute__((unused)) UInt id) const { return fe_engine::details::GetShapesHelper<kind>::call(shape_functions, type, ghost_type); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct GetShapesDerivativesHelper { template <template <ElementKind> class S, ElementKind k> static const Array<Real> & call(const S<k> &, const ElementType &, const GhostType &, UInt) { AKANTU_TO_IMPLEMENT(); } }; #define GET_SHAPES_DERIVATIVES(type) \ ret = &(shape_functions.getShapesDerivatives(type, ghost_type)); #define AKANTU_SPECIALIZE_GET_SHAPES_DERIVATIVES_HELPER(kind) \ template <> struct GetShapesDerivativesHelper<kind> { \ template <template <ElementKind> class S, ElementKind k> \ static const Array<Real> & \ call(const S<k> & shape_functions, const ElementType type, \ const GhostType & ghost_type, __attribute__((unused)) UInt id) { \ const Array<Real> * ret = NULL; \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_SHAPES_DERIVATIVES, kind); \ return *ret; \ } \ }; AKANTU_BOOST_ALL_KIND_LIST(AKANTU_SPECIALIZE_GET_SHAPES_DERIVATIVES_HELPER, AKANTU_FE_ENGINE_LIST_GET_SHAPES_DERIVATIVES) #undef AKANTU_SPECIALIZE_GET_SHAPE_DERIVATIVES_HELPER #undef GET_SHAPES_DERIVATIVES } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline const Array<Real> & FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::getShapesDerivatives( const ElementType & type, const GhostType & ghost_type, __attribute__((unused)) UInt id) const { return fe_engine::details::GetShapesDerivativesHelper<kind>::call( shape_functions, type, ghost_type, id); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct GetIntegrationPointsHelper {}; #define GET_INTEGRATION_POINTS(type) \ ret = &(integrator.template getIntegrationPoints<type>(ghost_type)); #define AKANTU_SPECIALIZE_GET_INTEGRATION_POINTS_HELPER(kind) \ template <> struct GetIntegrationPointsHelper<kind> { \ template <template <ElementKind, class> class I, ElementKind k, class IOF> \ static const Matrix<Real> & call(const I<k, IOF> & integrator, \ const ElementType type, \ const GhostType & ghost_type) { \ const Matrix<Real> * ret = NULL; \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_INTEGRATION_POINTS, kind); \ return *ret; \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_GET_INTEGRATION_POINTS_HELPER) #undef AKANTU_SPECIALIZE_GET_INTEGRATION_POINTS_HELPER #undef GET_INTEGRATION_POINTS } // namespace details } // namespace fe_engine template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline const Matrix<Real> & FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::getIntegrationPoints( const ElementType & type, const GhostType & ghost_type) const { return fe_engine::details::GetIntegrationPointsHelper<kind>::call( integrator, type, ghost_type); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::printself( std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "FEEngineTemplate [" << std::endl; stream << space << " + parent [" << std::endl; FEEngine::printself(stream, indent + 3); stream << space << " ]" << std::endl; stream << space << " + shape functions [" << std::endl; shape_functions.printself(stream, indent + 3); stream << space << " ]" << std::endl; stream << space << " + integrator [" << std::endl; integrator.printself(stream, indent + 3); stream << space << " ]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::onElementsAdded( const Array<Element> & new_elements, const NewElementsEvent &) { integrator.onElementsAdded(new_elements); shape_functions.onElementsAdded(new_elements); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::onElementsRemoved( const Array<Element> &, const ElementTypeMapArray<UInt> &, const RemovedElementsEvent &) {} /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::onElementsChanged( const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) {} /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: computeNormalsOnIntegrationPointsPoint1( const Array<Real> &, Array<Real> & normal, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mesh.getSpatialDimension() == 1, "Mesh dimension must be 1 to compute normals on points!"); const ElementType type = _point_1; UInt spatial_dimension = mesh.getSpatialDimension(); // UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_points = getNbIntegrationPoints(type, ghost_type); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); normal.resize(nb_element * nb_points); Array<Real>::matrix_iterator normals_on_quad = normal.begin_reinterpret(spatial_dimension, nb_points, nb_element); const Array<std::vector<Element>> & segments = mesh.getElementToSubelement(type, ghost_type); const Array<Real> & coords = mesh.getNodes(); const Mesh * mesh_segment; if (mesh.isMeshFacets()) mesh_segment = &(mesh.getMeshParent()); else mesh_segment = &mesh; for (UInt elem = 0; elem < nb_element; ++elem) { UInt nb_segment = segments(elem).size(); AKANTU_DEBUG_ASSERT( nb_segment > 0, "Impossible to compute a normal on a point connected to 0 segments"); Real normal_value = 1; if (nb_segment == 1) { const Element & segment = segments(elem)[0]; const Array<UInt> & segment_connectivity = mesh_segment->getConnectivity(segment.type, segment.ghost_type); // const Vector<UInt> & segment_points = // segment_connectivity.begin(Mesh::getNbNodesPerElement(segment.type))[segment.element]; Real difference; if (segment_connectivity(0) == elem) { difference = coords(elem) - coords(segment_connectivity(1)); } else { difference = coords(elem) - coords(segment_connectivity(0)); } normal_value = difference / std::abs(difference); } for (UInt n(0); n < nb_points; ++n) { (*normals_on_quad)(0, n) = normal_value; } ++normals_on_quad; } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/fe_engine/fe_engine_template_tmpl_field.hh b/src/fe_engine/fe_engine_template_tmpl_field.hh index 205071102..1cc83c4ae 100644 --- a/src/fe_engine/fe_engine_template_tmpl_field.hh +++ b/src/fe_engine/fe_engine_template_tmpl_field.hh @@ -1,426 +1,428 @@ /** * @file fe_engine_template_tmpl_field.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Tue Jul 25 2017 + * @date creation: Wed Aug 09 2017 + * @date last modification: Thu Dec 07 2017 * - * @brief implementation of the assemble field s functions + * @brief implementation of the assemble field s functions * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "fe_engine_template.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FE_ENGINE_TEMPLATE_TMPL_FIELD_HH__ #define __AKANTU_FE_ENGINE_TEMPLATE_TMPL_FIELD_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Matrix lumping functions */ /* -------------------------------------------------------------------------- */ namespace fe_engine { namespace details { namespace { template <class Functor> void fillField(const Functor & field_funct, Array<Real> & field, UInt nb_element, UInt nb_integration_points, const ElementType & type, const GhostType & ghost_type) { UInt nb_degree_of_freedom = field.getNbComponent(); field.resize(nb_integration_points * nb_element); auto field_it = field.begin_reinterpret( nb_degree_of_freedom, nb_integration_points, nb_element); Element el{type, 0, ghost_type}; for (; el.element < nb_element; ++el.element, ++field_it) { field_funct(*field_it, el); } } } // namespace } // namespace details } // namespace fe_engine /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct AssembleLumpedTemplateHelper {}; #define ASSEMBLE_LUMPED(type) \ fem.template assembleFieldLumped<Functor, type>(field_funct, lumped, dof_id, \ dof_manager, ghost_type) #define AKANTU_SPECIALIZE_ASSEMBLE_HELPER(kind) \ template <> struct AssembleLumpedTemplateHelper<kind> { \ template <template <ElementKind, class> class I, \ template <ElementKind> class S, ElementKind k, class IOF, \ class Functor> \ static void call(const FEEngineTemplate<I, S, k, IOF> & fem, \ const Functor & field_funct, const ID & lumped, \ const ID & dof_id, DOFManager & dof_manager, \ ElementType type, const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(ASSEMBLE_LUMPED, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_ASSEMBLE_HELPER) #undef AKANTU_SPECIALIZE_ASSEMBLE_HELPER #undef ASSEMBLE_LUMPED } // namespace details } // namespace fe_engine /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IOF> template <class Functor> void FEEngineTemplate<I, S, kind, IOF>::assembleFieldLumped( const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, ElementType type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); fe_engine::details::AssembleLumpedTemplateHelper<kind>::call( *this, field_funct, matrix_id, dof_id, dof_manager, type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> template <class Functor, ElementType type> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::assembleFieldLumped( const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt nb_degree_of_freedom = dof_manager.getDOFs(dof_id).getNbComponent(); UInt nb_element = mesh.getNbElement(type, ghost_type); UInt nb_integration_points = this->getNbIntegrationPoints(type); Array<Real> field(0, nb_degree_of_freedom); fe_engine::details::fillField(field_funct, field, nb_element, nb_integration_points, type, ghost_type); switch (type) { case _triangle_6: case _quadrangle_8: case _tetrahedron_10: case _hexahedron_20: case _pentahedron_15: this->template assembleLumpedDiagonalScaling<type>(field, matrix_id, dof_id, dof_manager, ghost_type); break; default: this->template assembleLumpedRowSum<type>(field, matrix_id, dof_id, dof_manager, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @f$ \tilde{M}_{i} = \sum_j M_{ij} = \sum_j \int \rho \varphi_i \varphi_j dV = * \int \rho \varphi_i dV @f$ */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: assembleLumpedRowSum(const Array<Real> & field, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt shapes_size = ElementClass<type>::getShapeSize(); UInt nb_degree_of_freedom = field.getNbComponent(); Array<Real> * field_times_shapes = new Array<Real>(0, shapes_size * nb_degree_of_freedom); shape_functions.template fieldTimesShapes<type>(field, *field_times_shapes, ghost_type); UInt nb_element = mesh.getNbElement(type, ghost_type); Array<Real> * int_field_times_shapes = new Array<Real>( nb_element, shapes_size * nb_degree_of_freedom, "inte_rho_x_shapes"); integrator.template integrate<type>( *field_times_shapes, *int_field_times_shapes, nb_degree_of_freedom * shapes_size, ghost_type, empty_filter); delete field_times_shapes; dof_manager.assembleElementalArrayToLumpedMatrix( dof_id, *int_field_times_shapes, matrix_id, type, ghost_type); delete int_field_times_shapes; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @f$ \tilde{M}_{i} = c * M_{ii} = \int_{V_e} \rho dV @f$ */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>:: assembleLumpedDiagonalScaling(const Array<Real> & field, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); const ElementType & type_p1 = ElementClass<type>::getP1ElementType(); UInt nb_nodes_per_element_p1 = Mesh::getNbNodesPerElement(type_p1); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = field.getNbComponent(); UInt nb_element = mesh.getNbElement(type, ghost_type); Vector<Real> nodal_factor(nb_nodes_per_element); #define ASSIGN_WEIGHT_TO_NODES(corner, mid) \ { \ for (UInt n = 0; n < nb_nodes_per_element_p1; n++) \ nodal_factor(n) = corner; \ for (UInt n = nb_nodes_per_element_p1; n < nb_nodes_per_element; n++) \ nodal_factor(n) = mid; \ } if (type == _triangle_6) ASSIGN_WEIGHT_TO_NODES(1. / 12., 1. / 4.); if (type == _tetrahedron_10) ASSIGN_WEIGHT_TO_NODES(1. / 32., 7. / 48.); if (type == _quadrangle_8) ASSIGN_WEIGHT_TO_NODES( 3. / 76., 16. / 76.); /** coeff. derived by scaling * the diagonal terms of the corresponding * consistent mass computed with 3x3 gauss points; * coeff. are (1./36., 8./36.) for 2x2 gauss points */ if (type == _hexahedron_20) ASSIGN_WEIGHT_TO_NODES( 7. / 248., 16. / 248.); /** coeff. derived by scaling * the diagonal terms of the corresponding * consistent mass computed with 3x3x3 gauss points; * coeff. are (1./40., * 1./15.) for 2x2x2 gauss points */ if (type == _pentahedron_15) { // coefficients derived by scaling the diagonal terms of the corresponding // consistent mass computed with 8 gauss points; for (UInt n = 0; n < nb_nodes_per_element_p1; n++) nodal_factor(n) = 51. / 2358.; Real mid_triangle = 192. / 2358.; Real mid_quadrangle = 300. / 2358.; nodal_factor(6) = mid_triangle; nodal_factor(7) = mid_triangle; nodal_factor(8) = mid_triangle; nodal_factor(9) = mid_quadrangle; nodal_factor(10) = mid_quadrangle; nodal_factor(11) = mid_quadrangle; nodal_factor(12) = mid_triangle; nodal_factor(13) = mid_triangle; nodal_factor(14) = mid_triangle; } if (nb_element == 0) { AKANTU_DEBUG_OUT(); return; } #undef ASSIGN_WEIGHT_TO_NODES /// compute @f$ \int \rho dV = \rho V @f$ for each element auto int_field = std::make_unique<Array<Real>>( field.size(), nb_degree_of_freedom, "inte_rho_x"); integrator.template integrate<type>(field, *int_field, nb_degree_of_freedom, ghost_type, empty_filter); /// distribute the mass of the element to the nodes auto lumped_per_node = std::make_unique<Array<Real>>( nb_element, nb_degree_of_freedom * nb_nodes_per_element, "mass_per_node"); auto int_field_it = int_field->begin(nb_degree_of_freedom); auto lumped_per_node_it = lumped_per_node->begin(nb_degree_of_freedom, nb_nodes_per_element); for (UInt e = 0; e < nb_element; ++e) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { Vector<Real> l = (*lumped_per_node_it)(n); l = *int_field_it; l *= nodal_factor(n); } ++int_field_it; ++lumped_per_node_it; } dof_manager.assembleElementalArrayToLumpedMatrix(dof_id, *lumped_per_node, matrix_id, type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Helper class to be able to write a partial specialization on the element kind */ namespace fe_engine { namespace details { template <ElementKind kind> struct AssembleFieldMatrixHelper {}; #define ASSEMBLE_MATRIX(type) \ fem.template assembleFieldMatrix<Functor, type>( \ field_funct, matrix_id, dof_id, dof_manager, ghost_type) #define AKANTU_SPECIALIZE_ASSEMBLE_FIELD_MATRIX_HELPER(kind) \ template <> struct AssembleFieldMatrixHelper<kind> { \ template <template <ElementKind, class> class I, \ template <ElementKind> class S, ElementKind k, class IOF, \ class Functor> \ static void call(const FEEngineTemplate<I, S, k, IOF> & fem, \ const Functor & field_funct, const ID & matrix_id, \ const ID & dof_id, DOFManager & dof_manager, \ ElementType type, const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(ASSEMBLE_MATRIX, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_SPECIALIZE_ASSEMBLE_FIELD_MATRIX_HELPER) #undef AKANTU_SPECIALIZE_ASSEMBLE_FIELD_MATRIX_HELPER #undef ASSEMBLE_MATRIX } // namespace details } // namespace fe_engine /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IOF> template <class Functor> void FEEngineTemplate<I, S, kind, IOF>::assembleFieldMatrix( const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, ElementType type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); fe_engine::details::AssembleFieldMatrixHelper<kind>::template call( *this, field_funct, matrix_id, dof_id, dof_manager, type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @f$ \tilde{M}_{i} = \sum_j M_{ij} = \sum_j \int \rho \varphi_i \varphi_j dV = * \int \rho \varphi_i dV @f$ */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> template <class Functor, ElementType type> void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::assembleFieldMatrix( const Functor & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt shapes_size = ElementClass<type>::getShapeSize(); UInt nb_degree_of_freedom = dof_manager.getDOFs(dof_id).getNbComponent(); UInt lmat_size = nb_degree_of_freedom * shapes_size; UInt nb_element = mesh.getNbElement(type, ghost_type); // \int N * N so degree 2 * degree of N const UInt polynomial_degree = 2 * ElementClassProperty<type>::polynomial_degree; // getting the integration points Matrix<Real> integration_points = integrator.template getIntegrationPoints<type, polynomial_degree>(); UInt nb_integration_points = integration_points.cols(); UInt vect_size = nb_integration_points * nb_element; // getting the shapes on the integration points Array<Real> shapes(0, shapes_size); shape_functions.template computeShapesOnIntegrationPoints<type>( mesh.getNodes(), integration_points, shapes, ghost_type); // Extending the shape functions /// \TODO move this in the shape functions as Voigt format shapes to have the /// code in common with the structural elements Array<Real> modified_shapes(vect_size, lmat_size * nb_degree_of_freedom, 0.); Array<Real> local_mat(vect_size, lmat_size * lmat_size); auto mshapes_it = modified_shapes.begin(nb_degree_of_freedom, lmat_size); auto shapes_it = shapes.begin(shapes_size); for (UInt q = 0; q < vect_size; ++q, ++mshapes_it, ++shapes_it) { for (UInt d = 0; d < nb_degree_of_freedom; ++d) { for (UInt s = 0; s < shapes_size; ++s) { (*mshapes_it)(d, s * nb_degree_of_freedom + d) = (*shapes_it)(s); } } } // getting the value to assemble on the integration points Array<Real> field(vect_size, nb_degree_of_freedom); fe_engine::details::fillField(field_funct, field, nb_element, nb_integration_points, type, ghost_type); // computing \rho * N mshapes_it = modified_shapes.begin(nb_degree_of_freedom, lmat_size); auto lmat = local_mat.begin(lmat_size, lmat_size); auto field_it = field.begin_reinterpret(nb_degree_of_freedom, field.size()); for (UInt q = 0; q < vect_size; ++q, ++lmat, ++mshapes_it, ++field_it) { const auto & rho = *field_it; const auto & N = *mshapes_it; auto & mat = *lmat; Matrix<Real> Nt = N.transpose(); for (UInt d = 0; d < Nt.cols(); ++d) { Nt(d) *= rho(d); } mat.template mul<false, false>(Nt, N); } // integrate the elemental values Array<Real> int_field_times_shapes(nb_element, lmat_size * lmat_size, "inte_rho_x_shapes"); this->integrator.template integrate<type, polynomial_degree>( local_mat, int_field_times_shapes, lmat_size * lmat_size, ghost_type); // assemble the elemental values to the matrix dof_manager.assembleElementalMatricesToMatrix( matrix_id, dof_id, int_field_times_shapes, type, ghost_type); AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_FE_ENGINE_TEMPLATE_TMPL_FIELD_HH__ */ diff --git a/src/fe_engine/fe_engine_template_tmpl_struct.hh b/src/fe_engine/fe_engine_template_tmpl_struct.hh index 410af8f66..e6318d1e5 100644 --- a/src/fe_engine/fe_engine_template_tmpl_struct.hh +++ b/src/fe_engine/fe_engine_template_tmpl_struct.hh @@ -1,99 +1,99 @@ /** * @file fe_engine_template_tmpl_struct.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jul 07 2014 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Template implementation of FEEngineTemplate for Structural Element * Kinds * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "shape_structural.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <ElementKind kind, typename = void> struct AssembleFieldMatrixStructHelper {}; template <ElementKind kind> struct AssembleFieldMatrixStructHelper< kind, typename std::enable_if<kind == _ek_structural>::type> { template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind k, class IOF> static void call(const FEEngineTemplate<I, S, k, IOF> & fem, const Array<Real> & field_1, UInt nb_degree_of_freedom, SparseMatrix & M, Array<Real> * n, ElementTypeMapArray<Real> & rotation_mat, const ElementType & type, const GhostType & ghost_type) { #define ASSEMBLE_MATRIX(type) \ fem.template assembleFieldMatrix<type>(field_1, nb_degree_of_freedom, M, n, \ rotation_mat, ghost_type) AKANTU_BOOST_KIND_ELEMENT_SWITCH(ASSEMBLE_MATRIX, _ek_structural); #undef ASSEMBLE_MATRIX } }; template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::assembleFieldMatrix( const Array<Real> & field_1, UInt nb_degree_of_freedom, SparseMatrix & M, Array<Real> * n, ElementTypeMapArray<Real> & rotation_mat, const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); AssembleFieldMatrixStructHelper<kind>::template call( *this, field_1, nb_degree_of_freedom, M, n, rotation_mat, type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::computeShapesMatrix( const ElementType &, UInt, UInt, Array<Real> *, UInt, UInt, UInt, const bool, const GhostType &) const { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <template <ElementKind, class> class I, template <ElementKind> class S, ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void FEEngineTemplate<I, S, kind, IntegrationOrderFunctor>::assembleFieldMatrix( const Array<Real> &, UInt, SparseMatrix &, Array<Real> *, ElementTypeMapArray<Real> &, const GhostType &) const { AKANTU_TO_IMPLEMENT(); } } // akantu diff --git a/src/fe_engine/gauss_integration.cc b/src/fe_engine/gauss_integration.cc index d4f4d8caf..ec718269d 100644 --- a/src/fe_engine/gauss_integration.cc +++ b/src/fe_engine/gauss_integration.cc @@ -1,238 +1,238 @@ /** - * @file integration_element.cc + * @file gauss_integration.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Thomas Menouillard <tmenouillard@stucky.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Thu Nov 05 2015 + * @date last modification: Mon Jun 19 2017 * - * @brief Definition of the integration constants, some of the value are taken + * @brief Definition of the integration constants, some of the value are taken * from r3.01.01 doc from Code Aster * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_class.hh" using std::sqrt; namespace akantu { /* clang-format off */ /* -------------------------------------------------------------------------- */ /* Points */ /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_point, 1>::quad_positions[] = {0}; template<> Real GaussIntegrationTypeData<_git_point, 1>::quad_weights[] = {1.}; /* -------------------------------------------------------------------------- */ /* Segments */ /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_segment, 1>::quad_positions[] = {0.}; template<> Real GaussIntegrationTypeData<_git_segment, 1>::quad_weights[] = {2.}; /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_segment, 2>::quad_positions[] = {-1./sqrt(3.), 1./sqrt(3.)}; template<> Real GaussIntegrationTypeData<_git_segment, 2>::quad_weights[] = {1., 1.}; /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_segment, 3>::quad_positions[] = {-sqrt(3./5.), 0., sqrt(3./5.)}; template<> Real GaussIntegrationTypeData<_git_segment, 3>::quad_weights[] = {5./9., 8./9., 5./9.}; /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_segment, 4>::quad_positions[] = {-sqrt((3. + 2.*sqrt(6./5.))/7.), -sqrt((3. - 2.*sqrt(6./5.))/7.), sqrt((3. - 2.*sqrt(6./5.))/7.), sqrt((3. + 2.*sqrt(6./5.))/7.)}; template<> Real GaussIntegrationTypeData<_git_segment, 4>::quad_weights[] = {(18. - sqrt(30.))/36., (18. + sqrt(30.))/36., (18. + sqrt(30.))/36., (18. - sqrt(30.))/36.}; /* -------------------------------------------------------------------------- */ /* Triangles */ /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_triangle, 1>::quad_positions[] = {1./3., 1./3.}; template<> Real GaussIntegrationTypeData<_git_triangle, 1>::quad_weights[] = {1./2.}; /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_triangle, 3>::quad_positions[] = {1./6., 1./6., 2./3., 1./6., 1./6., 2./3.}; template<> Real GaussIntegrationTypeData<_git_triangle, 3>::quad_weights[] = {1./6., 1./6., 1./6.}; /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_triangle, 4>::quad_positions[] = {1./5., 1./5., 3./5., 1./5., 1./5., 3./5., 1./3., 1./3.}; template<> Real GaussIntegrationTypeData<_git_triangle, 4>::quad_weights[] = {25./(24.*4.), 25./(24.*4.), 25./(24.*4.), -27/(24.*4.)}; /* -------------------------------------------------------------------------- */ /// Found those one in the TrigGaussRuleInfo from mathematica and matched them to the code aster values /// http://www.colorado.edu/engineering/CAS/courses.d/AFEM.d/AFEM.AppI.d/AFEM.AppI.pdf static const Real tri_6_a = (8. - std::sqrt(10.) + std::sqrt(38.-44.*std::sqrt(2./5.)))/18.; static const Real tri_6_b = (8. - std::sqrt(10.) - std::sqrt(38.-44.*std::sqrt(2./5.)))/18.; static const Real tri_6_w1 = (620. - std::sqrt(213125. - 53320.*std::sqrt(10.)))/7440.; static const Real tri_6_w2 = (620. + std::sqrt(213125. - 53320.*std::sqrt(10.)))/7440.; template<> Real GaussIntegrationTypeData<_git_triangle, 6>::quad_positions[] = {tri_6_b, tri_6_b, 1. - 2. * tri_6_b, tri_6_b, tri_6_b, 1. - 2. * tri_6_b, tri_6_a, 1. - 2. * tri_6_a, tri_6_a, tri_6_a, 1. - 2. * tri_6_a, tri_6_a}; template<> Real GaussIntegrationTypeData<_git_triangle, 6>::quad_weights[] = {tri_6_w1, tri_6_w1, tri_6_w1, tri_6_w2, tri_6_w2, tri_6_w2}; /* -------------------------------------------------------------------------- */ static const Real tri_7_a = (6. + std::sqrt(15.)) / 21.; static const Real tri_7_b = (6. - std::sqrt(15.)) / 21.; static const Real tri_7_w1 = (155. + std::sqrt(15.))/2400.; static const Real tri_7_w2 = (155. - std::sqrt(15.))/2400.; template<> Real GaussIntegrationTypeData<_git_triangle, 7>::quad_positions[] = { 1./3., 1./3., tri_7_a, tri_7_a, 1. - 2.*tri_7_a, tri_7_a, tri_7_a, 1. - 2.*tri_7_a, tri_7_b, tri_7_b, 1. - 2.*tri_7_b, tri_7_b, tri_7_b, 1. - 2.*tri_7_b}; template<> Real GaussIntegrationTypeData<_git_triangle, 7>::quad_weights[] = {9./80., tri_7_w1, tri_7_w1, tri_7_w1, tri_7_w2, tri_7_w2, tri_7_w2}; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* Tetrahedrons */ /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_tetrahedron, 1>::quad_positions[] = {1./4., 1./4., 1./4.}; template<> Real GaussIntegrationTypeData<_git_tetrahedron, 1>::quad_weights[] = {1./6.}; /* -------------------------------------------------------------------------- */ static const Real tet_4_a = (5. - std::sqrt(5.))/20.; static const Real tet_4_b = (5. + 3.*std::sqrt(5.))/20.; template<> Real GaussIntegrationTypeData<_git_tetrahedron, 4>::quad_positions[] = {tet_4_a, tet_4_a, tet_4_a, tet_4_b, tet_4_a, tet_4_a, tet_4_a, tet_4_b, tet_4_a, tet_4_a, tet_4_a, tet_4_b}; template<> Real GaussIntegrationTypeData<_git_tetrahedron, 4>::quad_weights[] = {1./24., 1./24., 1./24., 1./24.}; /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_tetrahedron, 5>::quad_positions[] = {1./4., 1./4., 1./4., 1./6., 1./6., 1./6., 1./6., 1./6., 1./2., 1./6., 1./2., 1./6., 1./2., 1./6., 1./6.,}; template<> Real GaussIntegrationTypeData<_git_tetrahedron, 5>::quad_weights[] = {-2./15., 3./40., 3./40., 3./40., 3./40.}; /* -------------------------------------------------------------------------- */ static const Real tet_15_a = (7. + std::sqrt(15.))/34.; static const Real tet_15_b = (13. - 3. * std::sqrt(15.))/34.; static const Real tet_15_c = (7. - std::sqrt(15.))/34.; static const Real tet_15_d = (13. + 3. * std::sqrt(15.))/34.; static const Real tet_15_e = (5. - std::sqrt(15.))/20.; static const Real tet_15_f = (5. + std::sqrt(15.))/20.; static const Real tet_15_w1 = (2665. - 14. * std::sqrt(15.))/226800.; static const Real tet_15_w2 = (2665. + 14. * std::sqrt(15.))/226800.; static const Real tet_15_w3 = 5./567.; template<> Real GaussIntegrationTypeData<_git_tetrahedron, 15>::quad_positions[] = {1./4., 1./4., 1./4., tet_15_a, tet_15_a, tet_15_a, tet_15_a, tet_15_a, tet_15_b, tet_15_a, tet_15_b, tet_15_a, tet_15_b, tet_15_a, tet_15_a, tet_15_c, tet_15_c, tet_15_c, tet_15_c, tet_15_c, tet_15_d, tet_15_c, tet_15_d, tet_15_c, tet_15_d, tet_15_c, tet_15_c, tet_15_e, tet_15_e, tet_15_f, tet_15_e, tet_15_f, tet_15_e, tet_15_f, tet_15_e, tet_15_e, tet_15_e, tet_15_f, tet_15_f, tet_15_f, tet_15_e, tet_15_f, tet_15_f, tet_15_f, tet_15_e}; template<> Real GaussIntegrationTypeData<_git_tetrahedron, 15>::quad_weights[] = {8./405., tet_15_w1, tet_15_w1, tet_15_w1, tet_15_w1, tet_15_w2, tet_15_w2, tet_15_w2, tet_15_w2, tet_15_w3, tet_15_w3, tet_15_w3, tet_15_w3, tet_15_w3, tet_15_w3}; /* -------------------------------------------------------------------------- */ /* Pentahedrons */ /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_pentahedron, 6>::quad_positions[] = {-1./sqrt(3.), 0.5, 0.5, -1./sqrt(3.), 0. , 0.5, -1./sqrt(3.), 0.5, 0., 1./sqrt(3.), 0.5, 0.5, 1./sqrt(3.), 0. , 0.5, 1./sqrt(3.), 0.5 ,0.}; template<> Real GaussIntegrationTypeData<_git_pentahedron, 6>::quad_weights[] = {1./6., 1./6., 1./6., 1./6., 1./6., 1./6.}; /* -------------------------------------------------------------------------- */ template<> Real GaussIntegrationTypeData<_git_pentahedron, 8>::quad_positions[] = {-sqrt(3.)/3., 1./3., 1./3., -sqrt(3.)/3., 0.6, 0.2, -sqrt(3.)/3., 0.2, 0.6, -sqrt(3.)/3., 0.2, 0.2, sqrt(3.)/3., 1./3., 1./3., sqrt(3.)/3., 0.6, 0.2, sqrt(3.)/3., 0.2, 0.6, sqrt(3.)/3., 0.2, 0.2}; template<> Real GaussIntegrationTypeData<_git_pentahedron, 8>::quad_weights[] = {-27./96., 25./96., 25./96., 25./96., -27./96., 25./96., 25./96., 25./96.}; /* -------------------------------------------------------------------------- */ static const Real pent_21_x = std::sqrt(3./5.); static const Real pent_21_a = (6. + std::sqrt(15.)) / 21.; static const Real pent_21_b = (6. - std::sqrt(15.)) / 21.; static const Real pent_21_w1_1 = 5./9.; static const Real pent_21_w2_1 = 8./9.; static const Real pent_21_w1_2 = (155. + std::sqrt(15.))/2400.; static const Real pent_21_w2_2 = (155. - std::sqrt(15.))/2400.; template<> Real GaussIntegrationTypeData<_git_pentahedron, 21>::quad_positions[] = {- pent_21_x, 1./3., 1./3., - pent_21_x, pent_21_a, pent_21_a, - pent_21_x, 1. - 2.*pent_21_a, pent_21_a, - pent_21_x, pent_21_a, 1. - 2.*pent_21_a, - pent_21_x, pent_21_b, pent_21_b, - pent_21_x, 1. - 2.*pent_21_b, pent_21_b, - pent_21_x, pent_21_b, 1. - 2.*pent_21_b, 0., 1./3., 1./3., 0., pent_21_a, pent_21_a, 0., 1. - 2.*pent_21_a, pent_21_a, 0., pent_21_a, 1. - 2.*pent_21_a, 0., pent_21_b, pent_21_b, 0., 1. - 2.*pent_21_b, pent_21_b, 0., pent_21_b, 1. - 2.*pent_21_b, pent_21_x, 1./3., 1./3., pent_21_x, pent_21_a, pent_21_a, pent_21_x, 1. - 2.*pent_21_a, pent_21_a, pent_21_x, pent_21_a, 1. - 2.*pent_21_a, pent_21_x, pent_21_b, pent_21_b, pent_21_x, 1. - 2.*pent_21_b, pent_21_b, pent_21_x, pent_21_b, 1. - 2.*pent_21_b}; template<> Real GaussIntegrationTypeData<_git_pentahedron, 21>::quad_weights[] = {pent_21_w1_1 * 9. / 80., pent_21_w1_1*pent_21_w1_2, pent_21_w1_1*pent_21_w1_2, pent_21_w1_1*pent_21_w1_2, pent_21_w1_1*pent_21_w2_2, pent_21_w1_1*pent_21_w2_2, pent_21_w1_1*pent_21_w2_2, pent_21_w2_1 * 9. / 80., pent_21_w1_2*pent_21_w1_2, pent_21_w1_2*pent_21_w1_2, pent_21_w1_2*pent_21_w1_2, pent_21_w1_2*pent_21_w2_2, pent_21_w1_2*pent_21_w2_2, pent_21_w1_2*pent_21_w2_2, pent_21_w1_1 * 9. / 80., pent_21_w1_1*pent_21_w1_2, pent_21_w1_1*pent_21_w1_2, pent_21_w1_1*pent_21_w1_2, pent_21_w1_1*pent_21_w2_2, pent_21_w1_1*pent_21_w2_2, pent_21_w1_1*pent_21_w2_2}; } // akantu diff --git a/src/fe_engine/gauss_integration_tmpl.hh b/src/fe_engine/gauss_integration_tmpl.hh index 6ddb1e673..7e9a17e10 100644 --- a/src/fe_engine/gauss_integration_tmpl.hh +++ b/src/fe_engine/gauss_integration_tmpl.hh @@ -1,272 +1,273 @@ /** * @file gauss_integration_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue May 10 10:48:21 2016 + * @date creation: Tue May 10 2016 + * @date last modification: Wed Nov 29 2017 * * @brief implementation of the gauss integration helpers * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GAUSS_INTEGRATION_TMPL_HH__ #define __AKANTU_GAUSS_INTEGRATION_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* GaussIntegrationElement */ /* -------------------------------------------------------------------------- */ namespace _aka_gauss_helpers { template <GaussIntegrationType type, UInt n> struct GaussIntegrationNbPoints {}; template <UInt n> struct GaussIntegrationNbPoints<_git_not_defined, n> { static const UInt nb_points = 0; }; template <UInt n> struct GaussIntegrationNbPoints<_git_point, n> { static const UInt nb_points = 1; }; template <UInt n> struct GaussIntegrationNbPoints<_git_segment, n> { static const UInt nb_points = (n + 1) / 2 + ((n + 1) % 2 ? 1 : 0); }; #define DECLARE_GAUSS_NB_POINTS(type, order, points) \ template <> struct GaussIntegrationNbPoints<type, order> { \ static const UInt nb_points = points; \ } #define DECLARE_GAUSS_NB_POINTS_PENT(type, order, xo, yo) \ template <> struct GaussIntegrationNbPoints<type, order> { \ static const UInt x_order = xo; \ static const UInt yz_order = yo; \ static const UInt nb_points = 1; \ } DECLARE_GAUSS_NB_POINTS(_git_triangle, 1, 1); DECLARE_GAUSS_NB_POINTS(_git_triangle, 2, 3); DECLARE_GAUSS_NB_POINTS(_git_triangle, 3, 4); DECLARE_GAUSS_NB_POINTS(_git_triangle, 4, 6); DECLARE_GAUSS_NB_POINTS(_git_triangle, 5, 7); DECLARE_GAUSS_NB_POINTS(_git_tetrahedron, 1, 1); DECLARE_GAUSS_NB_POINTS(_git_tetrahedron, 2, 4); DECLARE_GAUSS_NB_POINTS(_git_tetrahedron, 3, 5); DECLARE_GAUSS_NB_POINTS(_git_tetrahedron, 4, 15); DECLARE_GAUSS_NB_POINTS(_git_tetrahedron, 5, 15); DECLARE_GAUSS_NB_POINTS_PENT(_git_pentahedron, 1, 3, 2); // order 3 in x, order 2 in y and z DECLARE_GAUSS_NB_POINTS_PENT(_git_pentahedron, 2, 3, 2); // order 3 in x, order 2 in y and z DECLARE_GAUSS_NB_POINTS_PENT(_git_pentahedron, 3, 3, 3); // order 3 in x, order 3 in y and z DECLARE_GAUSS_NB_POINTS_PENT(_git_pentahedron, 4, 5, 5); // order 5 in x, order 5 in y and z DECLARE_GAUSS_NB_POINTS_PENT(_git_pentahedron, 5, 5, 5); // order 5 in x, order 5 in y and z template <GaussIntegrationType type, UInt n, UInt on = n, bool end_recurse = false> struct GaussIntegrationNbPointsHelper { static const UInt pnp = GaussIntegrationNbPoints<type, n>::nb_points; static const UInt order = n; static const UInt nb_points = pnp; }; template <GaussIntegrationType type, UInt n, UInt on> struct GaussIntegrationNbPointsHelper<type, n, on, true> { static const UInt nb_points = 0; }; /* ------------------------------------------------------------------------ */ /* Generic helper */ /* ------------------------------------------------------------------------ */ template <GaussIntegrationType type, UInt dimension, UInt n> struct GaussIntegrationTypeDataHelper { using git_np = GaussIntegrationNbPoints<type, n>; using git_data = GaussIntegrationTypeData<type, git_np::nb_points>; static UInt getNbQuadraturePoints() { return git_np::nb_points; } static const Matrix<Real> getQuadraturePoints() { return Matrix<Real>(git_data::quad_positions, dimension, git_np::nb_points); } static const Vector<Real> getWeights() { return Vector<Real>(git_data::quad_weights, git_np::nb_points); } }; /* ------------------------------------------------------------------------ */ /* helper for _segment _quadrangle _hexahedron */ /* ------------------------------------------------------------------------ */ template <UInt dimension, UInt dp> struct GaussIntegrationTypeDataHelper<_git_segment, dimension, dp> { using git_np = GaussIntegrationNbPoints<_git_segment, dp>; using git_data = GaussIntegrationTypeData<_git_segment, git_np::nb_points>; static UInt getNbQuadraturePoints() { return Math::pow<dimension>(git_np::nb_points); } static const Matrix<Real> getQuadraturePoints() { UInt tot_nquad = getNbQuadraturePoints(); UInt nquad = git_np::nb_points; Matrix<Real> quads(dimension, tot_nquad); Vector<Real> pos(git_data::quad_positions, nquad); UInt offset = 1; for (UInt d = 0; d < dimension; ++d) { for (UInt n = 0, q = 0; n < tot_nquad; ++n, q += offset) { UInt rq = q % tot_nquad + q / tot_nquad; quads(d, rq) = pos(n % nquad); } offset *= nquad; } return quads; } static const Vector<Real> getWeights() { UInt tot_nquad = getNbQuadraturePoints(); UInt nquad = git_np::nb_points; Vector<Real> quads_weights(tot_nquad, 1.); Vector<Real> weights(git_data::quad_weights, nquad); UInt offset = 1; for (UInt d = 0; d < dimension; ++d) { for (UInt n = 0, q = 0; n < tot_nquad; ++n, q += offset) { UInt rq = q % tot_nquad + q / tot_nquad; quads_weights(rq) *= weights(n % nquad); } offset *= nquad; } return quads_weights; } }; /* ------------------------------------------------------------------------ */ /* helper for _pentahedron */ /* ------------------------------------------------------------------------ */ template <UInt dimension, UInt dp> struct GaussIntegrationTypeDataHelper<_git_pentahedron, dimension, dp> { using git_info = GaussIntegrationNbPoints<_git_pentahedron, dp>; using git_np_seg = GaussIntegrationNbPoints<_git_segment, git_info::x_order>; using git_np_tri = GaussIntegrationNbPoints<_git_triangle, git_info::yz_order>; using git_data_seg = GaussIntegrationTypeData<_git_segment, git_np_seg::nb_points>; using git_data_tri = GaussIntegrationTypeData<_git_triangle, git_np_tri::nb_points>; static UInt getNbQuadraturePoints() { return git_np_seg::nb_points * git_np_tri::nb_points; } static const Matrix<Real> getQuadraturePoints() { UInt tot_nquad = getNbQuadraturePoints(); UInt nquad_seg = git_np_seg::nb_points; UInt nquad_tri = git_np_tri::nb_points; Matrix<Real> quads(dimension, tot_nquad); Matrix<Real> pos_seg_w(git_data_seg::quad_positions, 1, nquad_seg); Matrix<Real> pos_tri_w(git_data_tri::quad_positions, 2, nquad_tri); for (UInt ns = 0, q = 0; ns < nquad_seg; ++ns) { Vector<Real> pos_seg = pos_seg_w(ns); for (UInt nt = 0; nt < nquad_tri; ++nt, ++q) { Vector<Real> pos_tri = pos_tri_w(nt); Vector<Real> quad = quads(q); quad(_x) = pos_seg(_x); quad(_y) = pos_tri(_x); quad(_z) = pos_tri(_y); } } return quads; } static const Vector<Real> getWeights() { UInt tot_nquad = getNbQuadraturePoints(); UInt nquad_seg = git_np_seg::nb_points; UInt nquad_tri = git_np_tri::nb_points; Vector<Real> quads_weights(tot_nquad); Vector<Real> weight_seg(git_data_seg::quad_weights, nquad_seg); Vector<Real> weight_tri(git_data_tri::quad_weights, nquad_tri); for (UInt ns = 0, q = 0; ns < nquad_seg; ++ns) { for (UInt nt = 0; nt < nquad_tri; ++nt, ++q) { quads_weights(q) = weight_seg(ns) * weight_tri(nt); } } return quads_weights; } }; } template <ElementType element_type, UInt n> const Matrix<Real> GaussIntegrationElement<element_type, n>::getQuadraturePoints() { const InterpolationType itp_type = ElementClassProperty<element_type>::interpolation_type; using interpolation_property = InterpolationProperty<itp_type>; using data_helper = _aka_gauss_helpers::GaussIntegrationTypeDataHelper< ElementClassProperty<element_type>::gauss_integration_type, interpolation_property::natural_space_dimension, n>; Matrix<Real> tmp(data_helper::getQuadraturePoints()); return tmp; } /* -------------------------------------------------------------------------- */ template <ElementType element_type, UInt n> const Vector<Real> GaussIntegrationElement<element_type, n>::getWeights() { const InterpolationType itp_type = ElementClassProperty<element_type>::interpolation_type; using interpolation_property = InterpolationProperty<itp_type>; using data_helper = _aka_gauss_helpers::GaussIntegrationTypeDataHelper< ElementClassProperty<element_type>::gauss_integration_type, interpolation_property::natural_space_dimension, n>; Vector<Real> tmp(data_helper::getWeights()); return tmp; } /* -------------------------------------------------------------------------- */ template <ElementType element_type, UInt n> UInt GaussIntegrationElement<element_type, n>::getNbQuadraturePoints() { const InterpolationType itp_type = ElementClassProperty<element_type>::interpolation_type; using interpolation_property = InterpolationProperty<itp_type>; using data_helper = _aka_gauss_helpers::GaussIntegrationTypeDataHelper< ElementClassProperty<element_type>::gauss_integration_type, interpolation_property::natural_space_dimension, n>; return data_helper::getNbQuadraturePoints(); } } // akantu #endif /* __AKANTU_GAUSS_INTEGRATION_TMPL_HH__ */ diff --git a/src/fe_engine/geometrical_element_property.cc b/src/fe_engine/geometrical_element_property.cc index c7086bbed..60e7f11f8 100644 --- a/src/fe_engine/geometrical_element_property.cc +++ b/src/fe_engine/geometrical_element_property.cc @@ -1,60 +1,62 @@ /** * @file geometrical_element_property.cc * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Wed Nov 29 2017 + * @date creation: Wed Nov 29 2017 + * @date last modification: Thu Nov 30 2017 * - * @brief A Documented file. + * @brief A Documented file. * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ #include <boost/preprocessor.hpp> /* -------------------------------------------------------------------------- */ namespace akantu { #define AKANTU_INSTANTIATE_TYPES(r, data, type) \ constexpr std::array<UInt, ElementClass<type>::getNbFacetTypes()> \ GeometricalElementProperty< \ ElementClassProperty<type>::geometrical_type>::nb_facets; \ constexpr std::array<UInt, ElementClass<type>::getNbFacetTypes()> \ GeometricalElementProperty< \ ElementClassProperty<type>::geometrical_type>::nb_nodes_per_facet; \ constexpr std::array< \ UInt, detail::sizeFacetConnectivity<GeometricalElementProperty< \ ElementClassProperty<type>::geometrical_type>>()> \ GeometricalElementProperty<ElementClassProperty< \ type>::geometrical_type>::facet_connectivity_vect; \ constexpr std::array<ElementType, ElementClass<type>::getNbFacetTypes()> \ ElementClassExtraGeometryProperties<type>::facet_type; BOOST_PP_SEQ_FOR_EACH(AKANTU_INSTANTIATE_TYPES, _, (_not_defined)AKANTU_ek_regular_ELEMENT_TYPE) #if defined(AKANTU_COHESIVE_ELEMENT) BOOST_PP_SEQ_FOR_EACH(AKANTU_INSTANTIATE_TYPES, _, AKANTU_ek_cohesive_ELEMENT_TYPE) #endif } // akantu diff --git a/src/fe_engine/geometrical_element_property.hh b/src/fe_engine/geometrical_element_property.hh index e6f42d94e..d3a70224b 100644 --- a/src/fe_engine/geometrical_element_property.hh +++ b/src/fe_engine/geometrical_element_property.hh @@ -1,489 +1,488 @@ /** - * @file geometrical_element.cc + * @file geometrical_element_property.hh * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Thomas Menouillard <tmenouillard@stucky.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Thu Feb 21 2013 - * @date last modification: Thu Jan 21 2016 + * @date creation: Wed Nov 29 2017 * * @brief Specialization of the geometrical types * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ #include <array> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GEOMETRICAL_ELEMENT_PROPERTY_HH__ #define __AKANTU_GEOMETRICAL_ELEMENT_PROPERTY_HH__ namespace akantu { namespace detail { template <typename properties> constexpr size_t sizeFacetConnectivity() { size_t s = 0; for (size_t n = 0; n < properties::nb_facet_types; ++n) { s += properties::nb_facets[n] * properties::nb_nodes_per_facet[n]; } return s == 0 ? 1 : s; } } template <> struct GeometricalElementProperty<_gt_not_defined> { static constexpr UInt spatial_dimension{0}; static constexpr UInt nb_nodes_per_element{0}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{0}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{0}}; static constexpr std::array<UInt, 1> facet_connectivity_vect{{0}}; }; template <> struct GeometricalElementProperty<_gt_point> { static constexpr UInt spatial_dimension{0}; static constexpr UInt nb_nodes_per_element{1}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{1}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{1}}; static constexpr std::array<UInt, 1> facet_connectivity_vect{{0}}; }; template <> struct GeometricalElementProperty<_gt_segment_2> { static constexpr UInt spatial_dimension{1}; static constexpr UInt nb_nodes_per_element{2}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{1}}; static constexpr std::array<UInt, 2> facet_connectivity_vect{{0, 1}}; }; template <> struct GeometricalElementProperty<_gt_segment_3> { static constexpr UInt spatial_dimension{1}; static constexpr UInt nb_nodes_per_element{3}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{1}}; // clang-format off static constexpr std::array<UInt, 2> facet_connectivity_vect{{0, 1}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_triangle_3> { static constexpr UInt spatial_dimension{2}; static constexpr UInt nb_nodes_per_element{3}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{3}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{2}}; // clang-format off static constexpr std::array<UInt, 6> facet_connectivity_vect{{ 0, 1, 2, 1, 2, 0}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_triangle_6> { static constexpr UInt spatial_dimension{2}; static constexpr UInt nb_nodes_per_element{6}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{3}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{3}}; // clang-format off static constexpr std::array<UInt, 9> facet_connectivity_vect{{ 0, 1, 2, 1, 2, 0, 3, 4, 5}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_tetrahedron_4> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{4}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{4}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{3}}; // clang-format off static constexpr std::array<UInt, 12> facet_connectivity_vect{{ 0, 1, 2, 0, 2, 2, 0, 1, 1, 3, 3, 3}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_tetrahedron_10> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{10}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{4}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{6}}; // clang-format off static constexpr std::array<UInt, 6*4> facet_connectivity_vect{{ 0, 1, 2, 0, 2, 2, 0, 1, 1, 3, 3, 3, 6, 5, 6, 4, 5, 9, 7, 8, 4, 8, 9, 7}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_quadrangle_4> { static constexpr UInt spatial_dimension{2}; static constexpr UInt nb_nodes_per_element{4}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{4}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{2}}; // clang-format off static constexpr std::array<UInt, 2*4> facet_connectivity_vect{{ 0, 1, 2, 3, 1, 2, 3, 0}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_quadrangle_8> { static constexpr UInt spatial_dimension{2}; static constexpr UInt nb_nodes_per_element{8}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{4}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{3}}; // clang-format off static constexpr std::array<UInt, 4*3> facet_connectivity_vect{{ 0, 1, 2, 3, 1, 2, 3, 0, 4, 5, 6, 7}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_hexahedron_8> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{8}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{6}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{4}}; // clang-format off static constexpr std::array<UInt, 4*6> facet_connectivity_vect{{ 0, 0, 1, 2, 3, 4, 3, 1, 2, 3, 0, 5, 2, 5, 6, 7, 4, 6, 1, 4, 5, 6, 7, 7}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_hexahedron_20> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{20}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{6}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{8}}; // clang-format off static constexpr std::array<UInt, 8*6> facet_connectivity_vect{{ 0, 1, 2, 3, 0, 4, 1, 2, 3, 0, 3, 5, 5, 6, 7, 4, 2, 6, 4, 5, 6, 7, 1, 7, 8, 9, 10, 11, 11, 16, 13, 14, 15, 12, 10, 17, 16, 17, 18, 19, 9, 18, 12, 13, 14, 15, 8, 19}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_pentahedron_6> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{6}; static constexpr UInt nb_facet_types{2}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2, 3}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{3, 4}}; // clang-format off static constexpr std::array<UInt, 3*2 + 4*3> facet_connectivity_vect{{ // first type 0, 3, 2, 4, 1, 5, // second type 0, 0, 1, 1, 3, 2, 4, 5, 5, 3, 2, 4}}; // clang-format on }; template <> struct GeometricalElementProperty<_gt_pentahedron_15> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{15}; static constexpr UInt nb_facet_types{2}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2, 3}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{6, 8}}; // clang-format off static constexpr std::array<UInt, 6*2 + 8*3> facet_connectivity_vect{{ // first type 0, 3, 2, 4, 1, 5, 8, 12, 7, 13, 6, 14, // second type 0, 0, 1, 1, 3, 2, 4, 5, 5, 3, 2, 4, 6, 9, 7, 10, 14, 11, 12, 11, 13, 9, 8, 10}}; // clang-format on }; #if defined(AKANTU_COHESIVE_ELEMENT) /* -------------------------------------------------------------------------- */ template <> struct GeometricalElementProperty<_gt_cohesive_2d_4> { static constexpr UInt spatial_dimension{2}; static constexpr UInt nb_nodes_per_element{4}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{2}}; // clang-format off static constexpr std::array<UInt, 2 * 2> facet_connectivity_vect{{ 0, 2, 1, 3}}; // clang-format on }; /* -------------------------------------------------------------------------- */ template <> struct GeometricalElementProperty<_gt_cohesive_2d_6> { static constexpr UInt spatial_dimension{2}; static constexpr UInt nb_nodes_per_element{6}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{3}}; // clang-format off static constexpr std::array<UInt, 3*2> facet_connectivity_vect{{ 0, 3, 1, 4, 2, 5}}; // clang-format on }; /* -------------------------------------------------------------------------- */ template <> struct GeometricalElementProperty<_gt_cohesive_1d_2> { static constexpr UInt spatial_dimension{1}; static constexpr UInt nb_nodes_per_element{2}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{1}}; // clang-format off static constexpr std::array<UInt, 2> facet_connectivity_vect{{0, 1}}; // clang-format on }; /* -------------------------------------------------------------------------- */ template <> struct GeometricalElementProperty<_gt_cohesive_3d_6> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{6}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{3}}; // clang-format off static constexpr std::array<UInt, 3*2> facet_connectivity_vect{{ 0, 3, 1, 4, 2, 5}}; // clang-format on }; /* -------------------------------------------------------------------------- */ template <> struct GeometricalElementProperty<_gt_cohesive_3d_12> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{12}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{6}}; // clang-format off static constexpr std::array<UInt, 6*2> facet_connectivity_vect{{ 0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11}}; // clang-format on }; /* -------------------------------------------------------------------------- */ template <> struct GeometricalElementProperty<_gt_cohesive_3d_8> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{8}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{4}}; // clang-format off static constexpr std::array<UInt, 4*2> facet_connectivity_vect{{ 0, 4, 1, 5, 2, 6, 3, 7}}; // clang-format on }; /* -------------------------------------------------------------------------- */ template <> struct GeometricalElementProperty<_gt_cohesive_3d_16> { static constexpr UInt spatial_dimension{3}; static constexpr UInt nb_nodes_per_element{16}; static constexpr UInt nb_facet_types{1}; static constexpr std::array<UInt, nb_facet_types> nb_facets{{2}}; static constexpr std::array<UInt, nb_facet_types> nb_nodes_per_facet{{8}}; // clang-format off static constexpr std::array<UInt, 8*2> facet_connectivity_vect{{ 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15}}; // clang-format on }; #endif // AKANTU_COHESIVE_ELEMENT /* ------------------------------------------------------------------------ */ template <> struct ElementClassExtraGeometryProperties<_not_defined> { static constexpr ElementType p1_type{_not_defined}; static constexpr std::array<ElementType, 1> facet_type{{_not_defined}}; }; template <> struct ElementClassExtraGeometryProperties<_point_1> { static constexpr ElementType p1_type{_point_1}; static constexpr std::array<ElementType, 1> facet_type{{_point_1}}; }; template <> struct ElementClassExtraGeometryProperties<_segment_2> { static constexpr ElementType p1_type{_segment_2}; static constexpr std::array<ElementType, 1> facet_type{{_point_1}}; }; template <> struct ElementClassExtraGeometryProperties<_segment_3> { static constexpr ElementType p1_type{_segment_2}; static constexpr std::array<ElementType, 1> facet_type{{_point_1}}; }; template <> struct ElementClassExtraGeometryProperties<_triangle_3> { static constexpr ElementType p1_type{_triangle_3}; static constexpr std::array<ElementType, 1> facet_type{{_segment_2}}; }; template <> struct ElementClassExtraGeometryProperties<_triangle_6> { static constexpr ElementType p1_type{_triangle_3}; static constexpr std::array<ElementType, 1> facet_type{{_segment_3}}; }; template <> struct ElementClassExtraGeometryProperties<_tetrahedron_4> { static constexpr ElementType p1_type{_tetrahedron_4}; static constexpr std::array<ElementType, 1> facet_type{{_triangle_3}}; }; template <> struct ElementClassExtraGeometryProperties<_tetrahedron_10> { static constexpr ElementType p1_type{_tetrahedron_4}; static constexpr std::array<ElementType, 1> facet_type{{_triangle_6}}; }; template <> struct ElementClassExtraGeometryProperties<_quadrangle_4> { static constexpr ElementType p1_type{_quadrangle_4}; static constexpr std::array<ElementType, 1> facet_type{{_segment_2}}; }; template <> struct ElementClassExtraGeometryProperties<_quadrangle_8> { static constexpr ElementType p1_type{_quadrangle_4}; static constexpr std::array<ElementType, 1> facet_type{{_segment_3}}; }; template <> struct ElementClassExtraGeometryProperties<_hexahedron_8> { static constexpr ElementType p1_type{_hexahedron_8}; static constexpr std::array<ElementType, 1> facet_type{{_quadrangle_4}}; }; template <> struct ElementClassExtraGeometryProperties<_hexahedron_20> { static constexpr ElementType p1_type{_hexahedron_8}; static constexpr std::array<ElementType, 1> facet_type{{_quadrangle_8}}; }; template <> struct ElementClassExtraGeometryProperties<_pentahedron_6> { static constexpr ElementType p1_type{_pentahedron_6}; static constexpr std::array<ElementType, 2> facet_type{ {_triangle_3, _quadrangle_4}}; }; template <> struct ElementClassExtraGeometryProperties<_pentahedron_15> { static constexpr ElementType p1_type{_pentahedron_6}; static constexpr std::array<ElementType, 2> facet_type{ {_triangle_6, _quadrangle_8}}; }; #if defined(AKANTU_COHESIVE_ELEMENT) template <> struct ElementClassExtraGeometryProperties<_cohesive_2d_4> { static constexpr ElementType p1_type{_cohesive_2d_4}; static constexpr std::array<ElementType, 1> facet_type{{_segment_2}}; }; template <> struct ElementClassExtraGeometryProperties<_cohesive_2d_6> { static constexpr ElementType p1_type{_cohesive_2d_4}; static constexpr std::array<ElementType, 1> facet_type{{_segment_3}}; }; template <> struct ElementClassExtraGeometryProperties<_cohesive_1d_2> { static constexpr ElementType p1_type{_cohesive_1d_2}; static constexpr std::array<ElementType, 1> facet_type{{_point_1}}; }; template <> struct ElementClassExtraGeometryProperties<_cohesive_3d_6> { static constexpr ElementType p1_type{_cohesive_3d_6}; static constexpr std::array<ElementType, 1> facet_type{{_triangle_3}}; }; template <> struct ElementClassExtraGeometryProperties<_cohesive_3d_12> { static constexpr ElementType p1_type{_cohesive_3d_6}; static constexpr std::array<ElementType, 1> facet_type{{_triangle_6}}; }; template <> struct ElementClassExtraGeometryProperties<_cohesive_3d_8> { static constexpr ElementType p1_type{_cohesive_3d_8}; static constexpr std::array<ElementType, 1> facet_type{{_quadrangle_4}}; }; template <> struct ElementClassExtraGeometryProperties<_cohesive_3d_16> { static constexpr ElementType p1_type{_cohesive_3d_8}; static constexpr std::array<ElementType, 1> facet_type{{_quadrangle_8}}; }; #endif // AKANTU_COHESIVE_ELEMENT } // namespace akantu #endif /* __AKANTU_GEOMETRICAL_ELEMENT_PROPERTY_HH__ */ diff --git a/src/fe_engine/integration_point.hh b/src/fe_engine/integration_point.hh index 9c8eb8056..0e09a5b89 100644 --- a/src/fe_engine/integration_point.hh +++ b/src/fe_engine/integration_point.hh @@ -1,169 +1,170 @@ /** * @file integration_point.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Jun 17 2015 - * @date last modification: Sun Nov 15 2015 + * @date last modification: Wed Nov 08 2017 * * @brief definition of the class IntegrationPoint * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_types.hh" #include "element.hh" /* -------------------------------------------------------------------------- */ #ifndef AKANTU_QUADRATURE_POINT_H #define AKANTU_QUADRATURE_POINT_H /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ class IntegrationPoint; extern const IntegrationPoint IntegrationPointNull; /* -------------------------------------------------------------------------- */ class IntegrationPoint : public Element { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using position_type = Vector<Real>; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: IntegrationPoint(const Element & element, UInt num_point = 0, UInt nb_quad_per_element = 0) : Element(element), num_point(num_point), global_num(element.element * nb_quad_per_element + num_point), position(nullptr, 0){}; IntegrationPoint(ElementType type = _not_defined, UInt element = 0, UInt num_point = 0, GhostType ghost_type = _not_ghost) : Element{type, element, ghost_type}, num_point(num_point), position(nullptr, 0){}; IntegrationPoint(UInt element, UInt num_point, UInt global_num, const position_type & position, ElementType type, GhostType ghost_type = _not_ghost) : Element{type, element, ghost_type}, num_point(num_point), global_num(global_num), position(nullptr, 0) { this->position.shallowCopy(position); }; IntegrationPoint(const IntegrationPoint & quad) : Element(quad), num_point(quad.num_point), global_num(quad.global_num), position(nullptr, 0) { position.shallowCopy(quad.position); }; virtual ~IntegrationPoint() = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ inline bool operator==(const IntegrationPoint & quad) const { return Element::operator==(quad) && this->num_point == quad.num_point; } inline bool operator!=(const IntegrationPoint & quad) const { return Element::operator!=(quad) || (num_point != quad.num_point) || (global_num != quad.global_num); } bool operator<(const IntegrationPoint & rhs) const { bool res = Element::operator<(rhs) || (Element::operator==(rhs) && this->num_point < rhs.num_point); return res; } inline IntegrationPoint & operator=(const IntegrationPoint & q) { if (this != &q) { element = q.element; type = q.type; ghost_type = q.ghost_type; num_point = q.num_point; global_num = q.global_num; position.shallowCopy(q.position); } return *this; } /// get the position of the integration point AKANTU_GET_MACRO(Position, position, const position_type &); /// set the position of the integration point void setPosition(const position_type & position) { this->position.shallowCopy(position); } /// deep copy of the position of the integration point void copyPosition(const position_type & position) { this->position.deepCopy(position); } /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "IntegrationPoint ["; stream << *static_cast<const Element *>(this); stream << ", " << num_point << "(" << global_num << ")" << "]"; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: /// number of quadrature point in the element UInt num_point; /// global number of the quadrature point UInt global_num{0}; // TODO might be temporary: however this class should be tought maybe... std::string material_id; private: /// position of the quadrature point position_type position; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const IntegrationPoint & _this) { _this.printself(stream); return stream; } } // akantu #endif /* AKANTU_QUADRATURE_POINT_H */ diff --git a/src/fe_engine/integrator.hh b/src/fe_engine/integrator.hh index a9071ffe0..c751cfff4 100644 --- a/src/fe_engine/integrator.hh +++ b/src/fe_engine/integrator.hh @@ -1,136 +1,135 @@ /** * @file integrator.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Sun Dec 03 2017 * * @brief interface for integrator classes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_INTEGRATOR_HH__ #define __AKANTU_INTEGRATOR_HH__ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Integrator : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Integrator(const Mesh & mesh, const ID & id = "integrator", const MemoryID & memory_id = 0) : Memory(id, memory_id), mesh(mesh), jacobians("jacobians", id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); }; ~Integrator() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// empty method template <ElementType type> inline void precomputeJacobiansOnQuadraturePoints(__attribute__((unused)) GhostType ghost_type) {} /// empty method void integrateOnElement(const Array<Real> & /*f*/, Real * /*intf*/, UInt /*nb_degree_of_freedom*/, const Element & /*elem*/, GhostType /*ghost_type*/) const {}; /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Integrator [" << std::endl; jacobians.printself(stream, indent + 1); stream << space << "]" << std::endl; }; /* ------------------------------------------------------------------------ */ public: virtual void onElementsAdded(const Array<Element> &) {} virtual void onElementsRemoved(const Array<Element> &, const ElementTypeMapArray<UInt> & new_numbering) { jacobians.onElementsRemoved(new_numbering); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// access to the jacobians Array<Real> & getJacobians(const ElementType & type, const GhostType & ghost_type = _not_ghost) { return jacobians(type, ghost_type); }; /// access to the jacobians const const Array<Real> & getJacobians(const ElementType & type, const GhostType & ghost_type = _not_ghost) const { return jacobians(type, ghost_type); }; AKANTU_GET_MACRO(Jacobians, jacobians, const ElementTypeMapArray<Real> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// mesh associated to the integrator const Mesh & mesh; /// jacobians for all elements ElementTypeMapArray<Real> jacobians; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ //#include "integrator_inline_impl.cc" /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Integrator & _this) { _this.printself(stream); return stream; } } // namespace akantu #endif /* __AKANTU_INTEGRATOR_HH__ */ diff --git a/src/fe_engine/integrator_gauss.hh b/src/fe_engine/integrator_gauss.hh index 4b76a5962..469f19832 100644 --- a/src/fe_engine/integrator_gauss.hh +++ b/src/fe_engine/integrator_gauss.hh @@ -1,199 +1,199 @@ /** * @file integrator_gauss.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Gauss integration facilities * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "integrator.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTEGRATOR_GAUSS_HH__ #define __AKANTU_INTEGRATOR_GAUSS_HH__ namespace akantu { namespace integrator { namespace details { template <ElementKind> struct GaussIntegratorComputeJacobiansHelper; } // namespace details } // namespace fe_engine /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> class IntegratorGauss : public Integrator { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: IntegratorGauss(const Mesh & mesh, const ID & id = "integrator_gauss", const MemoryID & memory_id = 0); ~IntegratorGauss() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initIntegrator(const Array<Real> & nodes, const ElementType & type, const GhostType & ghost_type); template <ElementType type> inline void initIntegrator(const Array<Real> & nodes, const GhostType & ghost_type); /// integrate f on the element "elem" of type "type" template <ElementType type> inline void integrateOnElement(const Array<Real> & f, Real * intf, UInt nb_degree_of_freedom, const UInt elem, const GhostType & ghost_type) const; /// integrate f for all elements of type "type" template <ElementType type> void integrate(const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type, const Array<UInt> & filter_elements) const; /// integrate scalar field in_f template <ElementType type, UInt polynomial_degree> Real integrate(const Array<Real> & in_f, const GhostType & ghost_type = _not_ghost) const; /// integrate partially around a quadrature point (@f$ intf_q = f_q * J_q * /// w_q @f$) template <ElementType type> Real integrate(const Vector<Real> & in_f, UInt index, const GhostType & ghost_type) const; /// integrate scalar field in_f template <ElementType type> Real integrate(const Array<Real> & in_f, const GhostType & ghost_type, const Array<UInt> & filter_elements) const; /// integrate a field without using the pre-computed values template <ElementType type, UInt polynomial_degree> void integrate(const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type) const; /// integrate partially around a quadrature point (@f$ intf_q = f_q * J_q * /// w_q @f$) template <ElementType type> void integrateOnIntegrationPoints(const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type, const Array<UInt> & filter_elements) const; /// return a matrix with quadrature points natural coordinates template <ElementType type> const Matrix<Real> & getIntegrationPoints(const GhostType & ghost_type) const; /// return number of quadrature points template <ElementType type> UInt getNbIntegrationPoints(const GhostType & ghost_type) const; template <ElementType type, UInt n> Matrix<Real> getIntegrationPoints() const; template <ElementType type, UInt n> Vector<Real> getIntegrationWeights() const; protected: friend struct integrator::details::GaussIntegratorComputeJacobiansHelper< kind>; template <ElementType type> void computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const; void computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const; /// precompute jacobians on elements of type "type" template <ElementType type> void precomputeJacobiansOnQuadraturePoints(const Array<Real> & nodes, const GhostType & ghost_type); // multiply the jacobians by the integration weights and stores the results in // jacobians template <ElementType type, UInt polynomial_degree> void multiplyJacobiansByWeights(Array<Real> & jacobians) const; /// compute the vector of quadrature points natural coordinates template <ElementType type> void computeQuadraturePoints(const GhostType & ghost_type); /// check that the jacobians are not negative template <ElementType type> void checkJacobians(const GhostType & ghost_type) const; /// internal integrate partially around a quadrature point (@f$ intf_q = f_q * /// J_q * /// w_q @f$) void integrateOnIntegrationPoints(const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const Array<Real> & jacobians, UInt nb_element) const; void integrate(const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const Array<Real> & jacobians, UInt nb_element) const; public: /// compute the jacobians on quad points for a given element template <ElementType type> void computeJacobianOnQuadPointsByElement(const Matrix<Real> & node_coords, const Matrix<Real> & integration_points, Vector<Real> & jacobians) const; public: void onElementsAdded(const Array<Element> & elements) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// integrate the field f with the jacobian jac -> inte inline void integrate(Real * f, Real * jac, Real * inte, UInt nb_degree_of_freedom, UInt nb_quadrature_points) const; private: /// ElementTypeMap of the quadrature points ElementTypeMap<Matrix<Real>> quadrature_points; }; } // namespace akantu #include "integrator_gauss_inline_impl.cc" #endif /* __AKANTU_INTEGRATOR_GAUSS_HH__ */ diff --git a/src/fe_engine/integrator_gauss_inline_impl.cc b/src/fe_engine/integrator_gauss_inline_impl.cc index 681123e63..56fe0c8e3 100644 --- a/src/fe_engine/integrator_gauss_inline_impl.cc +++ b/src/fe_engine/integrator_gauss_inline_impl.cc @@ -1,709 +1,709 @@ /** * @file integrator_gauss_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Feb 15 2011 - * @date last modification: Thu Nov 19 2015 + * @date last modification: Tue Feb 20 2018 * * @brief inline function of gauss integrator * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "mesh_iterators.hh" #if defined(AKANTU_DEBUG_TOOLS) #include "aka_debug_tools.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { namespace debug { struct IntegratorGaussException : public Exception {}; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::integrateOnElement( const Array<Real> & f, Real * intf, UInt nb_degree_of_freedom, const UInt elem, const GhostType & ghost_type) const { Array<Real> & jac_loc = jacobians(type, ghost_type); UInt nb_quadrature_points = ElementClass<type>::getNbQuadraturePoints(); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom, "The vector f do not have the good number of component."); Real * f_val = f.storage() + elem * f.getNbComponent(); Real * jac_val = jac_loc.storage() + elem * nb_quadrature_points; integrate(f_val, jac_val, intf, nb_degree_of_freedom, nb_quadrature_points); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline Real IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Vector<Real> & in_f, UInt index, const GhostType & ghost_type) const { const Array<Real> & jac_loc = jacobians(type, ghost_type); UInt nb_quadrature_points = GaussIntegrationElement<type>::getNbQuadraturePoints(); AKANTU_DEBUG_ASSERT(in_f.size() == nb_quadrature_points, "The vector f do not have nb_quadrature_points entries."); Real * jac_val = jac_loc.storage() + index * nb_quadrature_points; Real intf; integrate(in_f.storage(), jac_val, &intf, 1, nb_quadrature_points); return intf; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( Real * f, Real * jac, Real * inte, UInt nb_degree_of_freedom, UInt nb_quadrature_points) const { memset(inte, 0, nb_degree_of_freedom * sizeof(Real)); Real * cjac = jac; for (UInt q = 0; q < nb_quadrature_points; ++q) { for (UInt dof = 0; dof < nb_degree_of_freedom; ++dof) { inte[dof] += *f * *cjac; ++f; } ++cjac; } } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline const Matrix<Real> & IntegratorGauss<kind, IntegrationOrderFunctor>::getIntegrationPoints( const GhostType & ghost_type) const { AKANTU_DEBUG_ASSERT( quadrature_points.exists(type, ghost_type), "Quadrature points for type " << quadrature_points.printType(type, ghost_type) << " have not been initialized." << " Did you use 'computeQuadraturePoints' function ?"); return quadrature_points(type, ghost_type); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline UInt IntegratorGauss<kind, IntegrationOrderFunctor>::getNbIntegrationPoints( const GhostType & ghost_type) const { AKANTU_DEBUG_ASSERT( quadrature_points.exists(type, ghost_type), "Quadrature points for type " << quadrature_points.printType(type, ghost_type) << " have not been initialized." << " Did you use 'computeQuadraturePoints' function ?"); return quadrature_points(type, ghost_type).cols(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> inline Matrix<Real> IntegratorGauss<kind, IntegrationOrderFunctor>::getIntegrationPoints() const { return GaussIntegrationElement<type, polynomial_degree>::getQuadraturePoints(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> inline Vector<Real> IntegratorGauss<kind, IntegrationOrderFunctor>::getIntegrationWeights() const { return GaussIntegrationElement<type, polynomial_degree>::getWeights(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::computeQuadraturePoints( const GhostType & ghost_type) { Matrix<Real> & quads = quadrature_points(type, ghost_type); const UInt polynomial_degree = IntegrationOrderFunctor::template getOrder<type>(); quads = GaussIntegrationElement<type, polynomial_degree>::getQuadraturePoints(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>:: computeJacobianOnQuadPointsByElement(const Matrix<Real> & node_coords, const Matrix<Real> & quad, Vector<Real> & jacobians) const { // jacobian ElementClass<type>::computeJacobian(quad, node_coords, jacobians); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> IntegratorGauss<kind, IntegrationOrderFunctor>::IntegratorGauss( const Mesh & mesh, const ID & id, const MemoryID & memory_id) : Integrator(mesh, id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>::checkJacobians( const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = this->quadrature_points(type, ghost_type).cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); Real * jacobians_val = jacobians(type, ghost_type).storage(); for (UInt i = 0; i < nb_element * nb_quadrature_points; ++i, ++jacobians_val) { if (*jacobians_val < 0) AKANTU_CUSTOM_EXCEPTION_INFO(debug::IntegratorGaussException{}, "Negative jacobian computed," << " possible problem in the element " "node ordering (Quadrature Point " << i % nb_quadrature_points << ":" << i / nb_quadrature_points << ":" << type << ":" << ghost_type << ")"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = quad_points.cols(); UInt nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); auto jacobians_begin = jacobians_it; Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = x_el.begin(spatial_dimension, nb_nodes_per_element); nb_element = x_el.size(); // Matrix<Real> local_coord(spatial_dimension, nb_nodes_per_element); for (UInt elem = 0; elem < nb_element; ++elem, ++x_it) { const Matrix<Real> & x = *x_it; Vector<Real> & J = *jacobians_it; computeJacobianOnQuadPointsByElement<type>(x, quad_points, J); if (filter_elements == empty_filter) { ++jacobians_it; } else { jacobians_it = jacobians_begin + filter_elements(elem); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_STRUCTURAL_MECHANICS) template <> template <ElementType type> void IntegratorGauss<_ek_structural, DefaultIntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); const UInt spatial_dimension = mesh.getSpatialDimension(); const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const UInt nb_quadrature_points = quad_points.cols(); const UInt nb_dofs = ElementClass<type>::getNbDegreeOfFreedom(); UInt nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); auto jacobians_begin = jacobians_it; Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = x_el.begin(spatial_dimension, nb_nodes_per_element); nb_element = x_el.size(); const bool has_extra_normal = mesh.hasData<Real>("extra_normal", type, ghost_type); Array<Real>::const_vector_iterator extra_normal, extra_normal_begin; if (has_extra_normal) { extra_normal = mesh.getData<Real>("extra_normal", type, ghost_type) .begin(spatial_dimension); extra_normal_begin = extra_normal; } // Matrix<Real> local_coord(spatial_dimension, nb_nodes_per_element); for (UInt elem = 0; elem < nb_element; ++elem, ++x_it) { const Matrix<Real> & X = *x_it; Vector<Real> & J = *jacobians_it; Matrix<Real> R(nb_dofs, nb_dofs); if (has_extra_normal) ElementClass<type>::computeRotationMatrix(R, X, *extra_normal); else ElementClass<type>::computeRotationMatrix(R, X, Vector<Real>(X.rows())); // Extracting relevant lines auto x = (R.block(0, 0, spatial_dimension, spatial_dimension) * X) .block(0, 0, ElementClass<type>::getNaturalSpaceDimension(), ElementClass<type>::getNbNodesPerElement()); computeJacobianOnQuadPointsByElement<type>(x, quad_points, J); if (filter_elements == empty_filter) { ++jacobians_it; ++extra_normal; } else { jacobians_it = jacobians_begin + filter_elements(elem); extra_normal = extra_normal_begin + filter_elements(elem); } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) template <> template <ElementType type> void IntegratorGauss<_ek_cohesive, DefaultIntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = quad_points.cols(); UInt nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); auto jacobians_begin = jacobians_it; Vector<Real> weights = GaussIntegrationElement<type>::getWeights(); Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = x_el.begin(spatial_dimension, nb_nodes_per_element); UInt nb_nodes_per_subelement = nb_nodes_per_element / 2; Matrix<Real> x(spatial_dimension, nb_nodes_per_subelement); nb_element = x_el.size(); auto compute = [&](const auto & el) { Vector<Real> J(jacobians_begin[el]); for (UInt s = 0; s < spatial_dimension; ++s) for (UInt n = 0; n < nb_nodes_per_subelement; ++n) x(s, n) = ((*x_it)(s, n) + (*x_it)(s, n + nb_nodes_per_subelement)) * .5; if (type == _cohesive_1d_2) J(0) = 1; else this->computeJacobianOnQuadPointsByElement<type>(x, quad_points, J); }; for_each_element(nb_element, filter_elements, compute); AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>:: precomputeJacobiansOnQuadraturePoints(const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Array<Real> & jacobians_tmp = jacobians.alloc(0, 1, type, ghost_type); this->computeJacobiansOnIntegrationPoints<type>( nodes, quadrature_points(type, ghost_type), jacobians_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> void IntegratorGauss<kind, IntegrationOrderFunctor>::multiplyJacobiansByWeights( Array<Real> & jacobians) const { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = GaussIntegrationElement<type, polynomial_degree>::getNbQuadraturePoints(); UInt nb_element = jacobians.size() / nb_quadrature_points; Vector<Real> weights = GaussIntegrationElement<type, polynomial_degree>::getWeights(); auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); auto jacobians_end = jacobians.end_reinterpret(nb_quadrature_points, nb_element); for (; jacobians_it != jacobians_end; ++jacobians_it) { Vector<Real> & J = *jacobians_it; J *= weights; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const Array<Real> & jacobians, UInt nb_element) const { AKANTU_DEBUG_IN(); intf.resize(nb_element); if (nb_element == 0) return; UInt nb_points = jacobians.size() / nb_element; Array<Real>::const_matrix_iterator J_it; Array<Real>::matrix_iterator inte_it; Array<Real>::const_matrix_iterator f_it; f_it = in_f.begin_reinterpret(nb_degree_of_freedom, nb_points, nb_element); inte_it = intf.begin_reinterpret(nb_degree_of_freedom, 1, nb_element); J_it = jacobians.begin_reinterpret(nb_points, 1, nb_element); for (UInt el = 0; el < nb_element; ++el, ++J_it, ++f_it, ++inte_it) { const Matrix<Real> & f = *f_it; const Matrix<Real> & J = *J_it; Matrix<Real> & inte_f = *inte_it; inte_f.mul<false, false>(f, J); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); const Array<Real> & jac_loc = jacobians(type, ghost_type); if (filter_elements != empty_filter) { UInt nb_element = filter_elements.size(); Array<Real> * filtered_J = new Array<Real>(0, jac_loc.getNbComponent()); FEEngine::filterElementalData(mesh, jac_loc, *filtered_J, type, ghost_type, filter_elements); this->integrate(in_f, intf, nb_degree_of_freedom, *filtered_J, nb_element); delete filtered_J; } else { UInt nb_element = mesh.getNbElement(type, ghost_type); this->integrate(in_f, intf, nb_degree_of_freedom, jac_loc, nb_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); Matrix<Real> quads = this->getIntegrationPoints<type, polynomial_degree>(); Array<Real> jacobians; this->computeJacobiansOnIntegrationPoints<type>(mesh.getNodes(), quads, jacobians, ghost_type); this->multiplyJacobiansByWeights<type, polynomial_degree>(jacobians); this->integrate(in_f, intf, nb_degree_of_freedom, jacobians, mesh.getNbElement(type, ghost_type)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> Real IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); Array<Real> intfv(0, 1); integrate<type, polynomial_degree>(in_f, intfv, 1, ghost_type); Real res = Math::reduce(intfv); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> Real IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); Array<Real> intfv(0, 1); integrate<type>(in_f, intfv, 1, ghost_type, filter_elements); Real res = Math::reduce(intfv); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>:: integrateOnIntegrationPoints(const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const Array<Real> & jacobians, UInt nb_element) const { AKANTU_DEBUG_IN(); UInt nb_points = jacobians.size() / nb_element; intf.resize(nb_element * nb_points); auto J_it = jacobians.begin(); auto f_it = in_f.begin(nb_degree_of_freedom); auto inte_it = intf.begin(nb_degree_of_freedom); for (UInt el = 0; el < nb_element; ++el, ++J_it, ++f_it, ++inte_it) { const Real & J = *J_it; const Vector<Real> & f = *f_it; Vector<Real> & inte_f = *inte_it; inte_f = f; inte_f *= J; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>:: integrateOnIntegrationPoints(const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); const Array<Real> & jac_loc = this->jacobians(type, ghost_type); if (filter_elements != empty_filter) { UInt nb_element = filter_elements.size(); Array<Real> * filtered_J = new Array<Real>(0, jac_loc.getNbComponent()); FEEngine::filterElementalData(mesh, jac_loc, *filtered_J, type, ghost_type, filter_elements); this->integrateOnIntegrationPoints(in_f, intf, nb_degree_of_freedom, *filtered_J, nb_element); } else { UInt nb_element = mesh.getNbElement(type, ghost_type); this->integrateOnIntegrationPoints(in_f, intf, nb_degree_of_freedom, jac_loc, nb_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>::onElementsAdded( const Array<Element> & new_elements) { const auto & nodes = mesh.getNodes(); for (auto elements_range : MeshElementsByTypes(new_elements)) { auto type = elements_range.getType(); auto ghost_type = elements_range.getGhostType(); if (mesh.getKind(type) != kind) continue; auto & elements = elements_range.getElements(); if (not jacobians.exists(type, ghost_type)) jacobians.alloc(0, 1, type, ghost_type); this->computeJacobiansOnIntegrationPoints( nodes, quadrature_points(type, ghost_type), jacobians(type, ghost_type), type, ghost_type, elements); } } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::initIntegrator( const Array<Real> & nodes, const GhostType & ghost_type) { computeQuadraturePoints<type>(ghost_type); precomputeJacobiansOnQuadraturePoints<type>(nodes, ghost_type); checkJacobians<type>(ghost_type); constexpr UInt polynomial_degree = IntegrationOrderFunctor::template getOrder<type>(); multiplyJacobiansByWeights<type, polynomial_degree>( this->jacobians(type, ghost_type)); } namespace integrator { namespace details { template <ElementKind kind> struct GaussIntegratorInitHelper {}; #define INIT_INTEGRATOR(type) \ _int.template initIntegrator<type>(nodes, ghost_type) #define AKANTU_GAUSS_INTERGRATOR_INIT_HELPER(kind) \ template <> struct GaussIntegratorInitHelper<kind> { \ template <ElementKind k, class IOF> \ static void call(IntegratorGauss<k, IOF> & _int, \ const Array<Real> & nodes, const ElementType & type, \ const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INIT_INTEGRATOR, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_GAUSS_INTERGRATOR_INIT_HELPER) #undef AKANTU_GAUSS_INTERGRATOR_INIT_HELPER #undef INIT_INTEGRATOR } // namespace details } // namespace integrator template <ElementKind kind, class IntegrationOrderFunctor> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::initIntegrator( const Array<Real> & nodes, const ElementType & type, const GhostType & ghost_type) { integrator::details::GaussIntegratorInitHelper<kind>::call(*this, nodes, type, ghost_type); } namespace integrator { namespace details { template <ElementKind kind> struct GaussIntegratorComputeJacobiansHelper {}; #define AKANTU_COMPUTE_JACOBIANS(type) \ _int.template computeJacobiansOnIntegrationPoints<type>( \ nodes, quad_points, jacobians, ghost_type, filter_elements); #define AKANTU_GAUSS_INTERGRATOR_COMPUTE_JACOBIANS(kind) \ template <> struct GaussIntegratorComputeJacobiansHelper<kind> { \ template <ElementKind k, class IOF> \ static void \ call(const IntegratorGauss<k, IOF> & _int, const Array<Real> & nodes, \ const Matrix<Real> & quad_points, Array<Real> & jacobians, \ const ElementType & type, const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(AKANTU_COMPUTE_JACOBIANS, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_GAUSS_INTERGRATOR_COMPUTE_JACOBIANS) #undef AKANTU_GAUSS_INTERGRATOR_COMPUTE_JACOBIANS #undef AKANTU_COMPUTE_JACOBIANS } // namespace details } // namespace integrator template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { integrator::details::GaussIntegratorComputeJacobiansHelper<kind>::call( *this, nodes, quad_points, jacobians, type, ghost_type, filter_elements); } } // namespace akantu diff --git a/src/fe_engine/interpolation_element_tmpl.hh b/src/fe_engine/interpolation_element_tmpl.hh index 9507deb58..febbb6ddd 100644 --- a/src/fe_engine/interpolation_element_tmpl.hh +++ b/src/fe_engine/interpolation_element_tmpl.hh @@ -1,73 +1,73 @@ /** * @file interpolation_element_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jun 06 2013 - * @date last modification: Tue Apr 07 2015 + * @date last modification: Wed Nov 29 2017 * * @brief interpolation property description * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTERPOLATION_ELEMENT_TMPL_HH__ #define __AKANTU_INTERPOLATION_ELEMENT_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Regular Elements */ /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_not_defined, _itk_not_defined, 0, 0); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_point_1, _itk_lagrangian, 1, 0); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_segment_2, _itk_lagrangian, 2, 1); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_segment_3, _itk_lagrangian, 3, 1); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_triangle_3, _itk_lagrangian, 3, 2); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_triangle_6, _itk_lagrangian, 6, 2); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_tetrahedron_4, _itk_lagrangian, 4, 3); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_tetrahedron_10, _itk_lagrangian, 10, 3); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_quadrangle_4, _itk_lagrangian, 4, 2); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_serendip_quadrangle_8, _itk_lagrangian, 8, 2); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_hexahedron_8, _itk_lagrangian, 8, 3); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_serendip_hexahedron_20, _itk_lagrangian, 20, 3); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_pentahedron_6, _itk_lagrangian, 6, 3); AKANTU_DEFINE_INTERPOLATION_TYPE_PROPERTY(_itp_lagrange_pentahedron_15, _itk_lagrangian, 15, 3); } // akantu #endif /* __AKANTU_INTERPOLATION_ELEMENT_TMPL_HH__ */ diff --git a/src/fe_engine/shape_cohesive.hh b/src/fe_engine/shape_cohesive.hh index 96e0867e9..45c4bfd40 100644 --- a/src/fe_engine/shape_cohesive.hh +++ b/src/fe_engine/shape_cohesive.hh @@ -1,183 +1,182 @@ /** * @file shape_cohesive.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Feb 15 2011 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Tue Feb 20 2018 * * @brief shape functions for cohesive elements description * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "shape_lagrange.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_COHESIVE_HH__ #define __AKANTU_SHAPE_COHESIVE_HH__ namespace akantu { struct CohesiveReduceFunctionMean { inline Real operator()(Real u_plus, Real u_minus) { return .5 * (u_plus + u_minus); } }; struct CohesiveReduceFunctionOpening { inline Real operator()(Real u_plus, Real u_minus) { return (u_plus - u_minus); } }; template <> class ShapeLagrange<_ek_cohesive> : public ShapeLagrangeBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ShapeLagrange(const Mesh & mesh, const ID & id = "shape_cohesive", const MemoryID & memory_id = 0); ~ShapeLagrange() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: inline void initShapeFunctions(const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type); /// extract the nodal values and store them per element template <ElementType type, class ReduceFunction> void extractNodalToElementField( const Array<Real> & nodal_f, Array<Real> & elemental_f, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; /// computes the shape functions derivatives for given interpolation points template <ElementType type> void computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const; void computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const override; /// pre compute all shapes on the element integration points from natural /// coordinates template <ElementType type> void precomputeShapesOnIntegrationPoints(const Array<Real> & nodes, GhostType ghost_type); /// pre compute all shape derivatives on the element integration points from /// natural coordinates template <ElementType type> void precomputeShapeDerivativesOnIntegrationPoints(const Array<Real> & nodes, GhostType ghost_type); /// interpolate nodal values on the integration points template <ElementType type, class ReduceFunction> void interpolateOnIntegrationPoints( const Array<Real> & u, Array<Real> & uq, UInt nb_degree_of_freedom, const GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; template <ElementType type> void interpolateOnIntegrationPoints( const Array<Real> & u, Array<Real> & uq, UInt nb_degree_of_freedom, const GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const { interpolateOnIntegrationPoints<type, CohesiveReduceFunctionMean>( u, uq, nb_degree_of_freedom, ghost_type, filter_elements); } /// compute the gradient of u on the integration points in the natural /// coordinates template <ElementType type> void gradientOnIntegrationPoints( const Array<Real> & u, Array<Real> & nablauq, UInt nb_degree_of_freedom, GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const { variationOnIntegrationPoints<type, CohesiveReduceFunctionMean>( u, nablauq, nb_degree_of_freedom, ghost_type, filter_elements); } template <ElementType type> void computeBtD(const Array<Real> & /*Ds*/, Array<Real> & /*BtDs*/, GhostType /*ghost_type*/, const Array<UInt> & /*filter_elements*/) const { AKANTU_TO_IMPLEMENT(); } template <ElementType type> void computeBtDB(const Array<Real> & /*Ds*/, Array<Real> & /*BtDBs*/, UInt /*order_d*/, GhostType /*ghost_type*/, const Array<UInt> & /*filter_elements*/) const { AKANTU_TO_IMPLEMENT(); } /// compute the gradient of u on the integration points template <ElementType type, class ReduceFunction> void variationOnIntegrationPoints( const Array<Real> & u, Array<Real> & nablauq, UInt nb_degree_of_freedom, GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; /// compute the normals to the field u on integration points template <ElementType type, class ReduceFunction> void computeNormalsOnIntegrationPoints( const Array<Real> & u, Array<Real> & normals_u, GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; /// multiply a field by shape functions template <ElementType type> void fieldTimesShapes(__attribute__((unused)) const Array<Real> & field, __attribute__((unused)) Array<Real> & fiedl_times_shapes, __attribute__((unused)) GhostType ghost_type) const { AKANTU_TO_IMPLEMENT(); } }; /// standard output stream operator template <class ShapeFunction> inline std::ostream & operator<<(std::ostream & stream, const ShapeCohesive<ShapeFunction> & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "shape_cohesive_inline_impl.cc" #endif /* __AKANTU_SHAPE_COHESIVE_HH__ */ diff --git a/src/fe_engine/shape_cohesive_inline_impl.cc b/src/fe_engine/shape_cohesive_inline_impl.cc index df81e9a8f..ad02dbffc 100644 --- a/src/fe_engine/shape_cohesive_inline_impl.cc +++ b/src/fe_engine/shape_cohesive_inline_impl.cc @@ -1,328 +1,328 @@ /** * @file shape_cohesive_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Feb 03 2012 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Mon Feb 19 2018 * * @brief ShapeCohesive inline implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "shape_cohesive.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__ #define __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline ShapeLagrange<_ek_cohesive>::ShapeLagrange(const Mesh & mesh, const ID & id, const MemoryID & memory_id) : ShapeLagrangeBase(mesh, _ek_cohesive, id, memory_id) {} #define INIT_SHAPE_FUNCTIONS(type) \ setIntegrationPointsByType<type>(integration_points, ghost_type); \ precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type); \ precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type); /* -------------------------------------------------------------------------- */ inline void ShapeLagrange<_ek_cohesive>::initShapeFunctions( const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type) { AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeLagrange<_ek_cohesive>::computeShapeDerivativesOnIntegrationPoints( const Array<Real> &, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize(); UInt spatial_dimension = ElementClass<type>::getNaturalSpaceDimension(); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); UInt nb_points = integration_points.cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); AKANTU_DEBUG_ASSERT(shape_derivatives.getNbComponent() == size_of_shapesd, "The shapes_derivatives array does not have the correct " << "number of component"); shape_derivatives.resize(nb_element * nb_points); Real * shapesd_val = shape_derivatives.storage(); auto compute = [&](const auto & el) { auto ptr = shapesd_val + el * nb_points * size_of_shapesd; Tensor3<Real> B(ptr, spatial_dimension, nb_nodes_per_element, nb_points); ElementClass<type>::computeDNDS(integration_points, B); }; for_each_element(nb_element, filter_elements, compute); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void ShapeLagrange<_ek_cohesive>::computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { #define AKANTU_COMPUTE_SHAPES(type) \ computeShapeDerivativesOnIntegrationPoints<type>( \ nodes, integration_points, shape_derivatives, ghost_type, \ filter_elements); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES); #undef AKANTU_COMPUTE_SHAPES } /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeLagrange<_ek_cohesive>::precomputeShapesOnIntegrationPoints( const Array<Real> & nodes, GhostType ghost_type) { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; Matrix<Real> & natural_coords = integration_points(type, ghost_type); UInt size_of_shapes = ElementClass<type>::getShapeSize(); Array<Real> & shapes_tmp = shapes.alloc(0, size_of_shapes, itp_type, ghost_type); this->computeShapesOnIntegrationPoints<type>(nodes, natural_coords, shapes_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeLagrange<_ek_cohesive>::precomputeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, GhostType ghost_type) { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; Matrix<Real> & natural_coords = integration_points(type, ghost_type); UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize(); Array<Real> & shapes_derivatives_tmp = shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); this->computeShapeDerivativesOnIntegrationPoints<type>( nodes, natural_coords, shapes_derivatives_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::extractNodalToElementField( const Array<Real> & nodal_f, Array<Real> & elemental_f, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_nodes_per_itp_element = ElementClass<type>::getNbNodesPerInterpolationElement(); UInt nb_degree_of_freedom = nodal_f.getNbComponent(); UInt nb_element = this->mesh.getNbElement(type, ghost_type); const auto & conn_array = this->mesh.getConnectivity(type, ghost_type); auto conn = conn_array.begin(conn_array.getNbComponent() / 2, 2); if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } elemental_f.resize(nb_element); Array<Real>::matrix_iterator u_it = elemental_f.begin(nb_degree_of_freedom, nb_nodes_per_itp_element); ReduceFunction reduce_function; auto compute = [&](const auto & el) { Matrix<Real> & u = *u_it; Matrix<UInt> el_conn(conn[el]); // compute the average/difference of the nodal field loaded from cohesive // element for (UInt n = 0; n < el_conn.rows(); ++n) { UInt node_plus = el_conn(n, 0); UInt node_minus = el_conn(n, 1); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { Real u_plus = nodal_f(node_plus, d); Real u_minus = nodal_f(node_minus, d); u(d, n) = reduce_function(u_plus, u_minus); } } ++u_it; }; for_each_element(nb_element, filter_elements, compute); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::interpolateOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; AKANTU_DEBUG_ASSERT(this->shapes.exists(itp_type, ghost_type), "No shapes for the type " << this->shapes.printType(itp_type, ghost_type)); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element); this->extractNodalToElementField<type, ReduceFunction>(in_u, u_el, ghost_type, filter_elements); this->template interpolateElementalFieldOnIntegrationPoints<type>( u_el, out_uq, ghost_type, shapes(itp_type, ghost_type), filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::variationOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & nablauq, UInt nb_degree_of_freedom, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; AKANTU_DEBUG_ASSERT( this->shapes_derivatives.exists(itp_type, ghost_type), "No shapes for the type " << this->shapes_derivatives.printType(itp_type, ghost_type)); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element); this->extractNodalToElementField<type, ReduceFunction>(in_u, u_el, ghost_type, filter_elements); this->template gradientElementalFieldOnIntegrationPoints<type>( u_el, nablauq, ghost_type, shapes_derivatives(itp_type, ghost_type), filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::computeNormalsOnIntegrationPoints( const Array<Real> & u, Array<Real> & normals_u, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_element = this->mesh.getNbElement(type, ghost_type); UInt nb_points = this->integration_points(type, ghost_type).cols(); UInt spatial_dimension = this->mesh.getSpatialDimension(); if (filter_elements != empty_filter) nb_element = filter_elements.size(); normals_u.resize(nb_points * nb_element); Array<Real> tangents_u(0, (spatial_dimension * (spatial_dimension - 1))); if (spatial_dimension > 1) { tangents_u.resize(nb_element * nb_points); this->template variationOnIntegrationPoints<type, ReduceFunction>( u, tangents_u, spatial_dimension, ghost_type, filter_elements); } Real * tangent = tangents_u.storage(); if (spatial_dimension == 3) { for (auto & normal : make_view(normals_u, spatial_dimension)) { Math::vectorProduct3(tangent, tangent + spatial_dimension, normal.storage()); normal /= normal.norm(); tangent += spatial_dimension * 2; } } else if (spatial_dimension == 2) { for (auto & normal : make_view(normals_u, spatial_dimension)) { Vector<Real> a1(tangent, spatial_dimension); normal(0) = -a1(1); normal(1) = a1(0); normal.normalize(); tangent += spatial_dimension; } } else if (spatial_dimension == 1) { const auto facet_type = Mesh::getFacetType(type); const auto & mesh_facets = mesh.getMeshFacets(); const auto & facets = mesh_facets.getSubelementToElement(type, ghost_type); const auto & segments = mesh_facets.getElementToSubelement(facet_type, ghost_type); Real values[2]; for (auto el : arange(nb_element)) { if (filter_elements != empty_filter) el = filter_elements(el); for (UInt p = 0; p < 2; ++p) { Element facet = facets(el, p); Element segment = segments(facet.element)[0]; Vector<Real> barycenter(values + p, 1); mesh.getBarycenter(segment, barycenter); } Real difference = values[0] - values[1]; AKANTU_DEBUG_ASSERT(difference != 0., "Error in normal computation for cohesive elements"); normals_u(el) = difference / std::abs(difference); } } AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/shape_functions.cc b/src/fe_engine/shape_functions.cc index 15d67f780..b45c222a9 100644 --- a/src/fe_engine/shape_functions.cc +++ b/src/fe_engine/shape_functions.cc @@ -1,243 +1,245 @@ /** * @file shape_functions.cc * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Thu Jul 27 2017 + * @date creation: Wed Aug 09 2017 + * @date last modification: Wed Oct 11 2017 * - * @brief implementation of th shape functions interface + * @brief implementation of th shape functions interface * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "shape_functions.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ShapeFunctions::ShapeFunctions(const Mesh & mesh, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), shapes("shapes_generic", id, memory_id), shapes_derivatives("shapes_derivatives_generic", id, memory_id), mesh(mesh) {} /* -------------------------------------------------------------------------- */ template <ElementType type> inline void ShapeFunctions::initElementalFieldInterpolationFromIntegrationPoints( const Array<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, const Array<Real> & quadrature_points_coordinates, const GhostType & ghost_type, const Array<UInt> & element_filter) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = this->mesh.getSpatialDimension(); UInt nb_element = this->mesh.getNbElement(type, ghost_type); UInt nb_element_filter; if (element_filter == empty_filter) nb_element_filter = nb_element; else nb_element_filter = element_filter.size(); UInt nb_quad_per_element = GaussIntegrationElement<type>::getNbQuadraturePoints(); UInt nb_interpolation_points_per_elem = interpolation_points_coordinates.size() / nb_element; AKANTU_DEBUG_ASSERT(interpolation_points_coordinates.size() % nb_element == 0, "Number of interpolation points should be a multiple of " "total number of elements"); if (!quad_points_coordinates_inv_matrices.exists(type, ghost_type)) quad_points_coordinates_inv_matrices.alloc( nb_element_filter, nb_quad_per_element * nb_quad_per_element, type, ghost_type); else quad_points_coordinates_inv_matrices(type, ghost_type) .resize(nb_element_filter); if (!interpolation_points_coordinates_matrices.exists(type, ghost_type)) interpolation_points_coordinates_matrices.alloc( nb_element_filter, nb_interpolation_points_per_elem * nb_quad_per_element, type, ghost_type); else interpolation_points_coordinates_matrices(type, ghost_type) .resize(nb_element_filter); Array<Real> & quad_inv_mat = quad_points_coordinates_inv_matrices(type, ghost_type); Array<Real> & interp_points_mat = interpolation_points_coordinates_matrices(type, ghost_type); Matrix<Real> quad_coord_matrix(nb_quad_per_element, nb_quad_per_element); Array<Real>::const_matrix_iterator quad_coords_it = quadrature_points_coordinates.begin_reinterpret( spatial_dimension, nb_quad_per_element, nb_element_filter); Array<Real>::const_matrix_iterator points_coords_begin = interpolation_points_coordinates.begin_reinterpret( spatial_dimension, nb_interpolation_points_per_elem, nb_element); Array<Real>::matrix_iterator inv_quad_coord_it = quad_inv_mat.begin(nb_quad_per_element, nb_quad_per_element); Array<Real>::matrix_iterator int_points_mat_it = interp_points_mat.begin( nb_interpolation_points_per_elem, nb_quad_per_element); /// loop over the elements of the current material and element type for (UInt el = 0; el < nb_element_filter; ++el, ++inv_quad_coord_it, ++int_points_mat_it, ++quad_coords_it) { /// matrix containing the quadrature points coordinates const Matrix<Real> & quad_coords = *quad_coords_it; /// matrix to store the matrix inversion result Matrix<Real> & inv_quad_coord_matrix = *inv_quad_coord_it; /// insert the quad coordinates in a matrix compatible with the /// interpolation buildElementalFieldInterpolationMatrix<type>(quad_coords, quad_coord_matrix); /// invert the interpolation matrix inv_quad_coord_matrix.inverse(quad_coord_matrix); /// matrix containing the interpolation points coordinates const Matrix<Real> & points_coords = points_coords_begin[element_filter(el)]; /// matrix to store the interpolation points coordinates /// compatible with these functions Matrix<Real> & inv_points_coord_matrix = *int_points_mat_it; /// insert the quad coordinates in a matrix compatible with the /// interpolation buildElementalFieldInterpolationMatrix<type>(points_coords, inv_points_coord_matrix); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ShapeFunctions::initElementalFieldInterpolationFromIntegrationPoints( const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, const ElementTypeMapArray<Real> & quadrature_points_coordinates, const ElementTypeMapArray<UInt> * element_filter) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = this->mesh.getSpatialDimension(); for (auto ghost_type : ghost_types) { Mesh::type_iterator it, last; if (element_filter) { it = element_filter->firstType(spatial_dimension, ghost_type); last = element_filter->lastType(spatial_dimension, ghost_type); } else { it = mesh.firstType(spatial_dimension, ghost_type); last = mesh.lastType(spatial_dimension, ghost_type); } for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, ghost_type); if (nb_element == 0) continue; const Array<UInt> * elem_filter; if (element_filter) elem_filter = &((*element_filter)(type, ghost_type)); else elem_filter = &(empty_filter); #define AKANTU_INIT_ELEMENTAL_FIELD_INTERPOLATION_FROM_C_POINTS(type) \ this->initElementalFieldInterpolationFromIntegrationPoints<type>( \ interpolation_points_coordinates(type, ghost_type), \ interpolation_points_coordinates_matrices, \ quad_points_coordinates_inv_matrices, \ quadrature_points_coordinates(type, ghost_type), ghost_type, \ *elem_filter) AKANTU_BOOST_REGULAR_ELEMENT_SWITCH( AKANTU_INIT_ELEMENTAL_FIELD_INTERPOLATION_FROM_C_POINTS); #undef AKANTU_INIT_ELEMENTAL_FIELD_INTERPOLATION_FROM_C_POINTS } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ShapeFunctions::interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, const ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, ElementTypeMapArray<Real> & result, const GhostType & ghost_type, const ElementTypeMapArray<UInt> * element_filter) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = this->mesh.getSpatialDimension(); Mesh::type_iterator it, last; if (element_filter) { it = element_filter->firstType(spatial_dimension, ghost_type); last = element_filter->lastType(spatial_dimension, ghost_type); } else { it = mesh.firstType(spatial_dimension, ghost_type); last = mesh.lastType(spatial_dimension, ghost_type); } for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, ghost_type); if (nb_element == 0) continue; const Array<UInt> * elem_filter; if (element_filter) elem_filter = &((*element_filter)(type, ghost_type)); else elem_filter = &(empty_filter); #define AKANTU_INTERPOLATE_ELEMENTAL_FIELD_FROM_C_POINTS(type) \ interpolateElementalFieldFromIntegrationPoints<type>( \ field(type, ghost_type), \ interpolation_points_coordinates_matrices(type, ghost_type), \ quad_points_coordinates_inv_matrices(type, ghost_type), result, \ ghost_type, *elem_filter) AKANTU_BOOST_REGULAR_ELEMENT_SWITCH( AKANTU_INTERPOLATE_ELEMENTAL_FIELD_FROM_C_POINTS); #undef AKANTU_INTERPOLATE_ELEMENTAL_FIELD_FROM_C_POINTS } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/fe_engine/shape_functions.hh b/src/fe_engine/shape_functions.hh index 8d2626a4a..1780f87b8 100644 --- a/src/fe_engine/shape_functions.hh +++ b/src/fe_engine/shape_functions.hh @@ -1,215 +1,214 @@ /** * @file shape_functions.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Tue Feb 20 2018 * * @brief shape function 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_FUNCTIONS_HH__ #define __AKANTU_SHAPE_FUNCTIONS_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ class ShapeFunctions : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ShapeFunctions(const Mesh & mesh, const ID & id = "shape", const MemoryID & memory_id = 0); ~ShapeFunctions() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Shapes [" << std::endl; integration_points.printself(stream, indent + 1); // shapes.printself(stream, indent + 1); // shapes_derivatives.printself(stream, indent + 1); stream << space << "]" << std::endl; } /// set the integration points for a given element template <ElementType type> void setIntegrationPointsByType(const Matrix<Real> & integration_points, const GhostType & ghost_type); /// Build pre-computed matrices for interpolation of field form integration /// points at other given positions (interpolation_points) void initElementalFieldInterpolationFromIntegrationPoints( const ElementTypeMapArray<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, const ElementTypeMapArray<Real> & quadrature_points_coordinates, const ElementTypeMapArray<UInt> * element_filter) const; /// Interpolate field at given position from given values of this field at /// integration points (field) /// using matrices precomputed with /// initElementalFieldInterplationFromIntegrationPoints void interpolateElementalFieldFromIntegrationPoints( const ElementTypeMapArray<Real> & field, const ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, const ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, ElementTypeMapArray<Real> & result, const GhostType & ghost_type, const ElementTypeMapArray<UInt> * element_filter) const; protected: /// interpolate nodal values stored by element on the integration points template <ElementType type> void interpolateElementalFieldOnIntegrationPoints( const Array<Real> & u_el, Array<Real> & uq, const GhostType & ghost_type, const Array<Real> & shapes, const Array<UInt> & filter_elements = empty_filter) const; /// gradient of nodal values stored by element on the control points template <ElementType type> void gradientElementalFieldOnIntegrationPoints( const Array<Real> & u_el, Array<Real> & out_nablauq, const GhostType & ghost_type, const Array<Real> & shapes_derivatives, const Array<UInt> & filter_elements) const; protected: /// By element versions of non-templated eponym methods template <ElementType type> inline void interpolateElementalFieldFromIntegrationPoints( const Array<Real> & field, const Array<Real> & interpolation_points_coordinates_matrices, const Array<Real> & quad_points_coordinates_inv_matrices, ElementTypeMapArray<Real> & result, const GhostType & ghost_type, const Array<UInt> & element_filter) const; /// Interpolate field at given position from given values of this field at /// integration points (field) /// using matrices precomputed with /// initElementalFieldInterplationFromIntegrationPoints template <ElementType type> inline void initElementalFieldInterpolationFromIntegrationPoints( const Array<Real> & interpolation_points_coordinates, ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices, ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices, const Array<Real> & quadrature_points_coordinates, const GhostType & ghost_type, const Array<UInt> & element_filter) const; /// build matrix for the interpolation of field form integration points template <ElementType type> inline void buildElementalFieldInterpolationMatrix( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order = ElementClassProperty<type>::polynomial_degree) const; /// build the so called interpolation matrix (first collumn is 1, then the /// other collumns are the traansposed coordinates) inline void buildInterpolationMatrix(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const; public: virtual void onElementsAdded(const Array<Element> &) { AKANTU_TO_IMPLEMENT(); } virtual void onElementsRemoved(const Array<Element> &, const ElementTypeMapArray<UInt> &) { AKANTU_TO_IMPLEMENT(); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the size of the shapes returned by the element class static inline UInt getShapeSize(const ElementType & type); /// get the size of the shapes derivatives returned by the element class static inline UInt getShapeDerivativesSize(const ElementType & type); inline const Matrix<Real> & getIntegrationPoints(const ElementType & type, const GhostType & ghost_type) const { return integration_points(type, ghost_type); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get a the shapes vector inline const Array<Real> & getShapes(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a the shapes derivatives vector inline const Array<Real> & getShapesDerivatives(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// shape functions for all elements ElementTypeMapArray<Real, InterpolationType> shapes; /// shape functions derivatives for all elements ElementTypeMapArray<Real, InterpolationType> shapes_derivatives; /// associated mesh const Mesh & mesh; /// shape functions for all elements ElementTypeMap<Matrix<Real>> integration_points; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const ShapeFunctions & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "shape_functions_inline_impl.cc" #endif /* __AKANTU_SHAPE_FUNCTIONS_HH__ */ diff --git a/src/fe_engine/shape_functions_inline_impl.cc b/src/fe_engine/shape_functions_inline_impl.cc index f7d05f8c4..84814402b 100644 --- a/src/fe_engine/shape_functions_inline_impl.cc +++ b/src/fe_engine/shape_functions_inline_impl.cc @@ -1,402 +1,401 @@ /** * @file shape_functions_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Fabian Barras <fabian.barras@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Oct 27 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief ShapeFunctions inline implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "shape_functions.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_FUNCTIONS_INLINE_IMPL_CC__ #define __AKANTU_SHAPE_FUNCTIONS_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline const Array<Real> & ShapeFunctions::getShapes(const ElementType & el_type, const GhostType & ghost_type) const { return shapes(FEEngine::getInterpolationType(el_type), ghost_type); } /* -------------------------------------------------------------------------- */ inline const Array<Real> & ShapeFunctions::getShapesDerivatives(const ElementType & el_type, const GhostType & ghost_type) const { return shapes_derivatives(FEEngine::getInterpolationType(el_type), ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt ShapeFunctions::getShapeSize(const ElementType & type) { AKANTU_DEBUG_IN(); UInt shape_size = 0; #define GET_SHAPE_SIZE(type) shape_size = ElementClass<type>::getShapeSize() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_SIZE); // , #undef GET_SHAPE_SIZE AKANTU_DEBUG_OUT(); return shape_size; } /* -------------------------------------------------------------------------- */ inline UInt ShapeFunctions::getShapeDerivativesSize(const ElementType & type) { AKANTU_DEBUG_IN(); UInt shape_derivatives_size = 0; #define GET_SHAPE_DERIVATIVES_SIZE(type) \ shape_derivatives_size = ElementClass<type>::getShapeDerivativesSize() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_SIZE); // , #undef GET_SHAPE_DERIVATIVES_SIZE AKANTU_DEBUG_OUT(); return shape_derivatives_size; } /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeFunctions::setIntegrationPointsByType(const Matrix<Real> & points, const GhostType & ghost_type) { if (not this->integration_points.exists(type, ghost_type)) this->integration_points(type, ghost_type).shallowCopy(points); } /* -------------------------------------------------------------------------- */ inline void ShapeFunctions::buildInterpolationMatrix(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { switch (integration_order) { case 1: { for (UInt i = 0; i < coordinates.cols(); ++i) coordMatrix(i, 0) = 1; break; } case 2: { UInt nb_quadrature_points = coordMatrix.cols(); for (UInt i = 0; i < coordinates.cols(); ++i) { coordMatrix(i, 0) = 1; for (UInt j = 1; j < nb_quadrature_points; ++j) coordMatrix(i, j) = coordinates(j - 1, i); } break; } default: { AKANTU_TO_IMPLEMENT(); break; } } } /* -------------------------------------------------------------------------- */ template <ElementType type> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix( const Matrix<Real> &, Matrix<Real> &, UInt) const { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_segment_2>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { buildInterpolationMatrix(coordinates, coordMatrix, integration_order); } /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_segment_3>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { buildInterpolationMatrix(coordinates, coordMatrix, integration_order); } /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_triangle_3>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { buildInterpolationMatrix(coordinates, coordMatrix, integration_order); } /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_triangle_6>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { buildInterpolationMatrix(coordinates, coordMatrix, integration_order); } /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_tetrahedron_4>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { buildInterpolationMatrix(coordinates, coordMatrix, integration_order); } /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_tetrahedron_10>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { buildInterpolationMatrix(coordinates, coordMatrix, integration_order); } /** * @todo Write a more efficient interpolation for quadrangles by * dropping unnecessary quadrature points * */ /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_quadrangle_4>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { if (integration_order != ElementClassProperty<_quadrangle_4>::polynomial_degree) { AKANTU_TO_IMPLEMENT(); } else { for (UInt i = 0; i < coordinates.cols(); ++i) { Real x = coordinates(0, i); Real y = coordinates(1, i); coordMatrix(i, 0) = 1; coordMatrix(i, 1) = x; coordMatrix(i, 2) = y; coordMatrix(i, 3) = x * y; } } } /* -------------------------------------------------------------------------- */ template <> inline void ShapeFunctions::buildElementalFieldInterpolationMatrix<_quadrangle_8>( const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix, UInt integration_order) const { if (integration_order != ElementClassProperty<_quadrangle_8>::polynomial_degree) { AKANTU_TO_IMPLEMENT(); } else { for (UInt i = 0; i < coordinates.cols(); ++i) { // UInt j = 0; Real x = coordinates(0, i); Real y = coordinates(1, i); coordMatrix(i, 0) = 1; coordMatrix(i, 1) = x; coordMatrix(i, 2) = y; coordMatrix(i, 3) = x * y; // for (UInt e = 0; e <= 2; ++e) { // for (UInt n = 0; n <= 2; ++n) { // coordMatrix(i, j) = std::pow(x, e) * std::pow(y, n); // ++j; // } // } } } } /* -------------------------------------------------------------------------- */ template <ElementType type> inline void ShapeFunctions::interpolateElementalFieldFromIntegrationPoints( const Array<Real> & field, const Array<Real> & interpolation_points_coordinates_matrices, const Array<Real> & quad_points_coordinates_inv_matrices, ElementTypeMapArray<Real> & result, const GhostType & ghost_type, const Array<UInt> & element_filter) const { AKANTU_DEBUG_IN(); auto nb_element = this->mesh.getNbElement(type, ghost_type); auto nb_quad_per_element = GaussIntegrationElement<type>::getNbQuadraturePoints(); auto nb_interpolation_points_per_elem = interpolation_points_coordinates_matrices.getNbComponent() / nb_quad_per_element; if (!result.exists(type, ghost_type)) result.alloc(nb_element * nb_interpolation_points_per_elem, field.getNbComponent(), type, ghost_type); if (element_filter != empty_filter) nb_element = element_filter.size(); Matrix<Real> coefficients(nb_quad_per_element, field.getNbComponent()); auto & result_vec = result(type, ghost_type); auto field_it = field.begin_reinterpret(field.getNbComponent(), nb_quad_per_element, nb_element); auto interpolation_points_coordinates_it = interpolation_points_coordinates_matrices.begin( nb_interpolation_points_per_elem, nb_quad_per_element); auto result_begin = result_vec.begin_reinterpret( field.getNbComponent(), nb_interpolation_points_per_elem, result_vec.size() / nb_interpolation_points_per_elem); auto inv_quad_coord_it = quad_points_coordinates_inv_matrices.begin( nb_quad_per_element, nb_quad_per_element); /// loop over the elements of the current filter and element type for (UInt el = 0; el < nb_element; ++el, ++field_it, ++inv_quad_coord_it, ++interpolation_points_coordinates_it) { /** * matrix containing the inversion of the quadrature points' * coordinates */ const auto & inv_quad_coord_matrix = *inv_quad_coord_it; /** * multiply it by the field values over quadrature points to get * the interpolation coefficients */ coefficients.mul<false, true>(inv_quad_coord_matrix, *field_it); /// matrix containing the points' coordinates const auto & coord = *interpolation_points_coordinates_it; /// multiply the coordinates matrix by the coefficients matrix and store the /// result Matrix<Real> res(result_begin[element_filter(el)]); res.mul<true, true>(coefficients, coord); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> inline void ShapeFunctions::interpolateElementalFieldOnIntegrationPoints( const Array<Real> & u_el, Array<Real> & uq, const GhostType & ghost_type, const Array<Real> & shapes, const Array<UInt> & filter_elements) const { auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_nodes_per_element = ElementClass<type>::getShapeSize(); auto nb_points = shapes.size() / mesh.getNbElement(type, ghost_type); auto nb_degree_of_freedom = u_el.getNbComponent() / nb_nodes_per_element; Array<Real>::const_matrix_iterator N_it; Array<Real> * filtered_N = nullptr; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); filtered_N = new Array<Real>(0, shapes.getNbComponent()); FEEngine::filterElementalData(mesh, shapes, *filtered_N, type, ghost_type, filter_elements); N_it = filtered_N->begin_reinterpret(nb_nodes_per_element, nb_points, nb_element); } else { N_it = shapes.begin_reinterpret(nb_nodes_per_element, nb_points, nb_element); } uq.resize(nb_element * nb_points); auto u_it = u_el.begin(nb_degree_of_freedom, nb_nodes_per_element); auto inter_u_it = uq.begin_reinterpret(nb_degree_of_freedom, nb_points, nb_element); for (UInt el = 0; el < nb_element; ++el, ++N_it, ++u_it, ++inter_u_it) { const auto & u = *u_it; const auto & N = *N_it; auto & inter_u = *inter_u_it; inter_u.template mul<false, false>(u, N); } delete filtered_N; } /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeFunctions::gradientElementalFieldOnIntegrationPoints( const Array<Real> & u_el, Array<Real> & out_nablauq, const GhostType & ghost_type, const Array<Real> & shapes_derivatives, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); auto nb_points = integration_points(type, ghost_type).cols(); auto element_dimension = ElementClass<type>::getNaturalSpaceDimension(); auto nb_degree_of_freedom = u_el.getNbComponent() / nb_nodes_per_element; auto nb_element = mesh.getNbElement(type, ghost_type); Array<Real>::const_matrix_iterator B_it; Array<Real> * filtered_B = nullptr; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); filtered_B = new Array<Real>(0, shapes_derivatives.getNbComponent()); FEEngine::filterElementalData(mesh, shapes_derivatives, *filtered_B, type, ghost_type, filter_elements); B_it = filtered_B->begin(element_dimension, nb_nodes_per_element); } else { B_it = shapes_derivatives.begin(element_dimension, nb_nodes_per_element); } out_nablauq.resize(nb_element * nb_points); auto u_it = u_el.begin(nb_degree_of_freedom, nb_nodes_per_element); auto nabla_u_it = out_nablauq.begin(nb_degree_of_freedom, element_dimension); for (UInt el = 0; el < nb_element; ++el, ++u_it) { const auto & u = *u_it; for (UInt q = 0; q < nb_points; ++q, ++B_it, ++nabla_u_it) { const auto & B = *B_it; auto & nabla_u = *nabla_u_it; nabla_u.template mul<false, true>(u, B); } } delete filtered_B; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_SHAPE_FUNCTIONS_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/shape_lagrange.hh b/src/fe_engine/shape_lagrange.hh index 36a3c321f..d3ff031d1 100644 --- a/src/fe_engine/shape_lagrange.hh +++ b/src/fe_engine/shape_lagrange.hh @@ -1,172 +1,172 @@ /** * @file shape_lagrange.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Feb 15 2011 - * @date last modification: Thu Nov 05 2015 + * @date last modification: Mon Jan 29 2018 * * @brief lagrangian shape functions 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "shape_lagrange_base.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_LAGRANGE_HH__ #define __AKANTU_SHAPE_LAGRANGE_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class Shape> class ShapeCohesive; class ShapeIGFEM; template <ElementKind kind> class ShapeLagrange : public ShapeLagrangeBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ShapeLagrange(const Mesh & mesh, const ID & id = "shape_lagrange", const MemoryID & memory_id = 0); ~ShapeLagrange() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialization function for structural elements not yet implemented inline void initShapeFunctions(const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type); /// computes the shape functions derivatives for given interpolation points template <ElementType type> void computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const; void computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const override; /// pre compute all shapes on the element integration points from natural /// coordinates template <ElementType type> void precomputeShapesOnIntegrationPoints(const Array<Real> & nodes, const GhostType & ghost_type); /// pre compute all shape derivatives on the element integration points from /// natural coordinates template <ElementType type> void precomputeShapeDerivativesOnIntegrationPoints(const Array<Real> & nodes, const GhostType & ghost_type); /// interpolate nodal values on the integration points template <ElementType type> void interpolateOnIntegrationPoints( const Array<Real> & u, Array<Real> & uq, UInt nb_degree_of_freedom, GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; template <ElementType type> void interpolateOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom, const Array<Real> & shapes, GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; /// interpolate on physical point template <ElementType type> void interpolate(const Vector<Real> & real_coords, UInt elem, const Matrix<Real> & nodal_values, Vector<Real> & interpolated, const GhostType & ghost_type) const; /// compute the gradient of u on the integration points template <ElementType type> void gradientOnIntegrationPoints( const Array<Real> & u, Array<Real> & nablauq, UInt nb_degree_of_freedom, GhostType ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; template <ElementType type> void computeBtD(const Array<Real> & Ds, Array<Real> & BtDs, GhostType ghost_type, const Array<UInt> & filter_elements) const; template <ElementType type> void computeBtDB(const Array<Real> & Ds, Array<Real> & BtDBs, UInt order_d, GhostType ghost_type, const Array<UInt> & filter_elements) const; /// multiply a field by shape functions @f$ fts_{ij} = f_i * \varphi_j @f$ template <ElementType type> void fieldTimesShapes(const Array<Real> & field, Array<Real> & field_times_shapes, GhostType ghost_type) const; /// find natural coords from real coords provided an element template <ElementType type> void inverseMap(const Vector<Real> & real_coords, UInt element, Vector<Real> & natural_coords, const GhostType & ghost_type = _not_ghost) const; /// return true if the coordinates provided are inside the element, false /// otherwise template <ElementType type> bool contains(const Vector<Real> & real_coords, UInt elem, const GhostType & ghost_type) const; /// compute the shape on a provided point template <ElementType type> void computeShapes(const Vector<Real> & real_coords, UInt elem, Vector<Real> & shapes, const GhostType & ghost_type) const; /// compute the shape derivatives on a provided point template <ElementType type> void computeShapeDerivatives(const Matrix<Real> & real_coords, UInt elem, Tensor3<Real> & shapes, const GhostType & ghost_type) const; protected: /// compute the shape derivatives on integration points for a given element template <ElementType type> inline void computeShapeDerivativesOnCPointsByElement(const Matrix<Real> & node_coords, const Matrix<Real> & natural_coords, Tensor3<Real> & shapesd) const; }; } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "shape_lagrange_inline_impl.cc" #endif /* __AKANTU_SHAPE_LAGRANGE_HH__ */ diff --git a/src/fe_engine/shape_lagrange_base.cc b/src/fe_engine/shape_lagrange_base.cc index 30fa00208..f2ef2f88a 100644 --- a/src/fe_engine/shape_lagrange_base.cc +++ b/src/fe_engine/shape_lagrange_base.cc @@ -1,158 +1,162 @@ /** * @file shape_lagrange_base.cc * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Thu Jul 27 2017 + * @date creation: Wed Aug 09 2017 + * @date last modification: Tue Feb 20 2018 + * + * @brief common par for the shape lagrange * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "shape_lagrange_base.hh" #include "mesh_iterators.hh" /* -------------------------------------------------------------------------- */ namespace akantu { ShapeLagrangeBase::ShapeLagrangeBase(const Mesh & mesh, const ElementKind & kind, const ID & id, const MemoryID & memory_id) : ShapeFunctions(mesh, id, memory_id), _kind(kind) {} /* -------------------------------------------------------------------------- */ ShapeLagrangeBase::~ShapeLagrangeBase() = default; /* -------------------------------------------------------------------------- */ #define AKANTU_COMPUTE_SHAPES(type) \ _this.template computeShapesOnIntegrationPoints<type>( \ nodes, integration_points, shapes, ghost_type, filter_elements) namespace shape_lagrange { namespace details { template <ElementKind kind> struct Helper { template <class S> static void call(const S &, const Array<Real> &, const Matrix<Real> &, Array<Real> &, const ElementType &, const GhostType &, const Array<UInt> &) { AKANTU_TO_IMPLEMENT(); } }; #define AKANTU_COMPUTE_SHAPES_KIND(kind) \ template <> struct Helper<kind> { \ template <class S> \ static void call(const S & _this, const Array<Real> & nodes, \ const Matrix<Real> & integration_points, \ Array<Real> & shapes, const ElementType & type, \ const GhostType & ghost_type, \ const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES, kind); \ } \ }; AKANTU_BOOST_ALL_KIND_LIST(AKANTU_COMPUTE_SHAPES_KIND, AKANTU_FE_ENGINE_LIST_LAGRANGE_BASE) } // namespace details } // namespace shape_lagrange /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::computeShapesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shapes, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { auto kind = Mesh::getKind(type); #define AKANTU_COMPUTE_SHAPES_KIND_SWITCH(kind) \ shape_lagrange::details::Helper<kind>::call( \ *this, nodes, integration_points, shapes, type, ghost_type, \ filter_elements); AKANTU_BOOST_LIST_SWITCH( AKANTU_COMPUTE_SHAPES_KIND_SWITCH, BOOST_PP_LIST_TO_SEQ(AKANTU_FE_ENGINE_LIST_LAGRANGE_BASE), kind); #undef AKANTU_COMPUTE_SHAPES #undef AKANTU_COMPUTE_SHAPES_KIND #undef AKANTU_COMPUTE_SHAPES_KIND_SWITCH } /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::onElementsAdded(const Array<Element> & new_elements) { AKANTU_DEBUG_IN(); const auto & nodes = mesh.getNodes(); for (auto elements_range : MeshElementsByTypes(new_elements)) { auto type = elements_range.getType(); auto ghost_type = elements_range.getGhostType(); if (mesh.getKind(type) != _kind) continue; auto & elements = elements_range.getElements(); auto itp_type = FEEngine::getInterpolationType(type); if (not this->shapes_derivatives.exists(itp_type, ghost_type)) { auto size_of_shapesd = this->getShapeDerivativesSize(type); this->shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); } if (not shapes.exists(itp_type, ghost_type)) { auto size_of_shapes = this->getShapeSize(type); this->shapes.alloc(0, size_of_shapes, itp_type, ghost_type); } const auto & natural_coords = integration_points(type, ghost_type); computeShapesOnIntegrationPoints(nodes, natural_coords, shapes(itp_type, ghost_type), type, ghost_type, elements); computeShapeDerivativesOnIntegrationPoints( nodes, natural_coords, shapes_derivatives(itp_type, ghost_type), type, ghost_type, elements); } #undef INIT_SHAPE_FUNCTIONS AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::onElementsRemoved( const Array<Element> &, const ElementTypeMapArray<UInt> & new_numbering) { this->shapes.onElementsRemoved(new_numbering); this->shapes_derivatives.onElementsRemoved(new_numbering); } /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Shapes Lagrange [" << std::endl; ShapeFunctions::printself(stream, indent + 1); shapes.printself(stream, indent + 1); shapes_derivatives.printself(stream, indent + 1); stream << space << "]" << std::endl; } } // namespace akantu diff --git a/src/fe_engine/shape_lagrange_base.hh b/src/fe_engine/shape_lagrange_base.hh index 08d915f7d..c50b27689 100644 --- a/src/fe_engine/shape_lagrange_base.hh +++ b/src/fe_engine/shape_lagrange_base.hh @@ -1,91 +1,92 @@ - /** * @file shape_lagrange_base.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Thu Jul 27 2017 + * @date creation: Wed Aug 09 2017 + * @date last modification: Wed Nov 08 2017 * - * @brief Base class for the shape lagrange + * @brief Base class for the shape lagrange * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "shape_functions.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_LAGRANGE_BASE_HH__ #define __AKANTU_SHAPE_LAGRANGE_BASE_HH__ namespace akantu { class ShapeLagrangeBase : public ShapeFunctions { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ShapeLagrangeBase(const Mesh & mesh, const ElementKind & kind, const ID & id = "shape_lagrange", const MemoryID & memory_id = 0); ~ShapeLagrangeBase() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// computes the shape functions for given interpolation points virtual void computeShapesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shapes, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const; /// computes the shape functions derivatives for given interpolation points virtual void computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const = 0; /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; template <ElementType type> void computeShapesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shapes, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const; public: void onElementsAdded(const Array<Element> & elements) override; void onElementsRemoved(const Array<Element> & elements, const ElementTypeMapArray<UInt> & new_numbering) override; protected: /// The kind to consider ElementKind _kind; }; } // namespace akantu #include "shape_lagrange_base_inline_impl.cc" #endif /* __AKANTU_SHAPE_LAGRANGE_BASE_HH__ */ diff --git a/src/fe_engine/shape_lagrange_base_inline_impl.cc b/src/fe_engine/shape_lagrange_base_inline_impl.cc index 4b9ebbf08..448d3b36a 100644 --- a/src/fe_engine/shape_lagrange_base_inline_impl.cc +++ b/src/fe_engine/shape_lagrange_base_inline_impl.cc @@ -1,82 +1,84 @@ /** * @file shape_lagrange_base_inline_impl.cc * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Thu Jul 27 2017 + * @date creation: Wed Aug 09 2017 + * @date last modification: Wed Oct 11 2017 * - * @brief A Documented file. + * @brief A Documented file. * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "shape_lagrange_base.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_LAGRANGE_BASE_INLINE_IMPL_CC__ #define __AKANTU_SHAPE_LAGRANGE_BASE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeLagrangeBase::computeShapesOnIntegrationPoints( const Array<Real> &, const Matrix<Real> & integration_points, Array<Real> & shapes, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_points = integration_points.cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); shapes.resize(nb_element * nb_points); #if !defined(AKANTU_NDEBUG) UInt size_of_shapes = ElementClass<type>::getShapeSize(); AKANTU_DEBUG_ASSERT(shapes.getNbComponent() == size_of_shapes, "The shapes array does not have the correct " << "number of component"); #endif auto shapes_it = shapes.begin_reinterpret( ElementClass<type>::getNbNodesPerInterpolationElement(), nb_points, nb_element); auto shapes_begin = shapes_it; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } for (UInt elem = 0; elem < nb_element; ++elem) { if (filter_elements != empty_filter) shapes_it = shapes_begin + filter_elements(elem); Matrix<Real> & N = *shapes_it; ElementClass<type>::computeShapes(integration_points, N); if (filter_elements == empty_filter) ++shapes_it; } AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_SHAPE_LAGRANGE_BASE_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/shape_lagrange_inline_impl.cc b/src/fe_engine/shape_lagrange_inline_impl.cc index e8b8aaba0..7a86db51f 100644 --- a/src/fe_engine/shape_lagrange_inline_impl.cc +++ b/src/fe_engine/shape_lagrange_inline_impl.cc @@ -1,526 +1,526 @@ /** * @file shape_lagrange_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Oct 27 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief ShapeLagrange inline implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "aka_voigthelper.hh" #include "fe_engine.hh" #include "shape_lagrange.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_LAGRANGE_INLINE_IMPL_CC__ #define __AKANTU_SHAPE_LAGRANGE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ #define INIT_SHAPE_FUNCTIONS(type) \ setIntegrationPointsByType<type>(integration_points, ghost_type); \ precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type); \ if (ElementClass<type>::getNaturalSpaceDimension() == \ mesh.getSpatialDimension() || \ kind != _ek_regular) \ precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type); template <ElementKind kind> inline void ShapeLagrange<kind>::initShapeFunctions( const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type) { AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS); } #undef INIT_SHAPE_FUNCTIONS /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> inline void ShapeLagrange<kind>::computeShapeDerivativesOnCPointsByElement( const Matrix<Real> & node_coords, const Matrix<Real> & natural_coords, Tensor3<Real> & shapesd) const { AKANTU_DEBUG_IN(); // compute dnds Tensor3<Real> dnds(node_coords.rows(), node_coords.cols(), natural_coords.cols()); ElementClass<type>::computeDNDS(natural_coords, dnds); // compute jacobian Tensor3<Real> J(node_coords.rows(), natural_coords.rows(), natural_coords.cols()); ElementClass<type>::computeJMat(dnds, node_coords, J); // compute dndx ElementClass<type>::computeShapeDerivatives(J, dnds, shapesd); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::inverseMap(const Vector<Real> & real_coords, UInt elem, Vector<Real> & natural_coords, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); UInt * elem_val = mesh.getConnectivity(type, ghost_type).storage(); Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element); mesh.extractNodalValuesFromElement(mesh.getNodes(), nodes_coord.storage(), elem_val + elem * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); ElementClass<type>::inverseMap(real_coords, nodes_coord, natural_coords); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> bool ShapeLagrange<kind>::contains(const Vector<Real> & real_coords, UInt elem, const GhostType & ghost_type) const { UInt spatial_dimension = mesh.getSpatialDimension(); Vector<Real> natural_coords(spatial_dimension); inverseMap<type>(real_coords, elem, natural_coords, ghost_type); return ElementClass<type>::contains(natural_coords); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::interpolate(const Vector<Real> & real_coords, UInt elem, const Matrix<Real> & nodal_values, Vector<Real> & interpolated, const GhostType & ghost_type) const { UInt nb_shapes = ElementClass<type>::getShapeSize(); Vector<Real> shapes(nb_shapes); computeShapes<type>(real_coords, elem, shapes, ghost_type); ElementClass<type>::interpolate(nodal_values, shapes, interpolated); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::computeShapes(const Vector<Real> & real_coords, UInt elem, Vector<Real> & shapes, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector<Real> natural_coords(spatial_dimension); inverseMap<type>(real_coords, elem, natural_coords, ghost_type); ElementClass<type>::computeShapes(natural_coords, shapes); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::computeShapeDerivatives( const Matrix<Real> & real_coords, UInt elem, Tensor3<Real> & shapesd, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_points = real_coords.cols(); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); AKANTU_DEBUG_ASSERT(mesh.getSpatialDimension() == shapesd.size(0) && nb_nodes_per_element == shapesd.size(1), "Shape size doesn't match"); AKANTU_DEBUG_ASSERT(nb_points == shapesd.size(2), "Number of points doesn't match shapes size"); Matrix<Real> natural_coords(spatial_dimension, nb_points); // Creates the matrix of natural coordinates for (UInt i = 0; i < nb_points; i++) { Vector<Real> real_point = real_coords(i); Vector<Real> natural_point = natural_coords(i); inverseMap<type>(real_point, elem, natural_point, ghost_type); } UInt * elem_val = mesh.getConnectivity(type, ghost_type).storage(); Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element); mesh.extractNodalValuesFromElement(mesh.getNodes(), nodes_coord.storage(), elem_val + elem * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); computeShapeDerivativesOnCPointsByElement<type>(nodes_coord, natural_coords, shapesd); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> ShapeLagrange<kind>::ShapeLagrange(const Mesh & mesh, const ID & id, const MemoryID & memory_id) : ShapeLagrangeBase(mesh, kind, id, memory_id) {} /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); UInt nb_points = integration_points.cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize(); AKANTU_DEBUG_ASSERT(shape_derivatives.getNbComponent() == size_of_shapesd, "The shapes_derivatives array does not have the correct " << "number of component"); shape_derivatives.resize(nb_element * nb_points); Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); Real * shapesd_val = shape_derivatives.storage(); Array<Real>::matrix_iterator x_it = x_el.begin(spatial_dimension, nb_nodes_per_element); if (filter_elements != empty_filter) nb_element = filter_elements.size(); for (UInt elem = 0; elem < nb_element; ++elem, ++x_it) { if (filter_elements != empty_filter) shapesd_val = shape_derivatives.storage() + filter_elements(elem) * size_of_shapesd * nb_points; Matrix<Real> & X = *x_it; Tensor3<Real> B(shapesd_val, spatial_dimension, nb_nodes_per_element, nb_points); computeShapeDerivativesOnCPointsByElement<type>(X, integration_points, B); if (filter_elements == empty_filter) shapesd_val += size_of_shapesd * nb_points; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> void ShapeLagrange<kind>::computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { #define AKANTU_COMPUTE_SHAPES(type) \ computeShapeDerivativesOnIntegrationPoints<type>( \ nodes, integration_points, shape_derivatives, ghost_type, \ filter_elements); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES); #undef AKANTU_COMPUTE_SHAPES } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::precomputeShapesOnIntegrationPoints( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; Matrix<Real> & natural_coords = integration_points(type, ghost_type); UInt size_of_shapes = ElementClass<type>::getShapeSize(); Array<Real> & shapes_tmp = shapes.alloc(0, size_of_shapes, itp_type, ghost_type); this->computeShapesOnIntegrationPoints<type>(nodes, natural_coords, shapes_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::precomputeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; Matrix<Real> & natural_coords = integration_points(type, ghost_type); UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize(); Array<Real> & shapes_derivatives_tmp = shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); this->computeShapeDerivativesOnIntegrationPoints<type>( nodes, natural_coords, shapes_derivatives_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::interpolateOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom, const Array<Real> & shapes, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); this->interpolateElementalFieldOnIntegrationPoints<type>( u_el, out_uq, ghost_type, shapes, filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::interpolateOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; AKANTU_DEBUG_ASSERT(shapes.exists(itp_type, ghost_type), "No shapes for the type " << shapes.printType(itp_type, ghost_type)); this->interpolateOnIntegrationPoints<type>(in_u, out_uq, nb_degree_of_freedom, shapes(itp_type, ghost_type), ghost_type, filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::gradientOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_nablauq, UInt nb_degree_of_freedom, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; AKANTU_DEBUG_ASSERT( shapes_derivatives.exists(itp_type, ghost_type), "No shapes derivatives for the type " << shapes_derivatives.printType(itp_type, ghost_type)); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); this->gradientElementalFieldOnIntegrationPoints<type>( u_el, out_nablauq, ghost_type, shapes_derivatives(itp_type, ghost_type), filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::computeBtD( const Array<Real> & Ds, Array<Real> & BtDs, GhostType ghost_type, const Array<UInt> & filter_elements) const { auto itp_type = ElementClassProperty<type>::interpolation_type; const auto & shapes_derivatives = this->shapes_derivatives(itp_type, ghost_type); auto spatial_dimension = mesh.getSpatialDimension(); auto nb_nodes_per_element = mesh.getNbNodesPerElement(type); Array<Real> shapes_derivatives_filtered(0, shapes_derivatives.getNbComponent()); auto && view = make_view(shapes_derivatives, spatial_dimension, nb_nodes_per_element); auto B_it = view.begin(); auto B_end = view.end(); if (filter_elements != empty_filter) { FEEngine::filterElementalData(this->mesh, shapes_derivatives, shapes_derivatives_filtered, type, ghost_type, filter_elements); auto && view = make_view(shapes_derivatives_filtered, spatial_dimension, nb_nodes_per_element); B_it = view.begin(); B_end = view.end(); } for (auto && values : zip(range(B_it, B_end), make_view(Ds, Ds.getNbComponent() / spatial_dimension, spatial_dimension), make_view(BtDs, BtDs.getNbComponent() / nb_nodes_per_element, nb_nodes_per_element))) { const auto & B = std::get<0>(values); const auto & D = std::get<1>(values); auto & Bt_D = std::get<2>(values); // transposed due to the storage layout of B Bt_D.template mul<false, false>(D, B); } } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::computeBtDB( const Array<Real> & Ds, Array<Real> & BtDBs, UInt order_d, GhostType ghost_type, const Array<UInt> & filter_elements) const { auto itp_type = ElementClassProperty<type>::interpolation_type; const auto & shapes_derivatives = this->shapes_derivatives(itp_type, ghost_type); constexpr auto dim = ElementClass<type>::getSpatialDimension(); auto nb_nodes_per_element = mesh.getNbNodesPerElement(type); Array<Real> shapes_derivatives_filtered(0, shapes_derivatives.getNbComponent()); auto && view = make_view(shapes_derivatives, dim, nb_nodes_per_element); auto B_it = view.begin(); auto B_end = view.end(); if (filter_elements != empty_filter) { FEEngine::filterElementalData(this->mesh, shapes_derivatives, shapes_derivatives_filtered, type, ghost_type, filter_elements); auto && view = make_view(shapes_derivatives_filtered, dim, nb_nodes_per_element); B_it = view.begin(); B_end = view.end(); } if (order_d == 4) { UInt tangent_size = VoigtHelper<dim>::size; Matrix<Real> B(tangent_size, dim * nb_nodes_per_element); Matrix<Real> Bt_D(dim * nb_nodes_per_element, tangent_size); for (auto && values : zip(range(B_it, B_end), make_view(Ds, tangent_size, tangent_size), make_view(BtDBs, dim * nb_nodes_per_element, dim * nb_nodes_per_element))) { const auto & Bfull = std::get<0>(values); const auto & D = std::get<1>(values); auto & Bt_D_B = std::get<2>(values); VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(Bfull, B, nb_nodes_per_element); Bt_D.template mul<true, false>(B, D); Bt_D_B.template mul<false, false>(Bt_D, B); } } else if (order_d == 2) { Matrix<Real> Bt_D(nb_nodes_per_element, dim); for (auto && values : zip(range(B_it, B_end), make_view(Ds, dim, dim), make_view(BtDBs, nb_nodes_per_element, nb_nodes_per_element))) { const auto & B = std::get<0>(values); const auto & D = std::get<1>(values); auto & Bt_D_B = std::get<2>(values); Bt_D.template mul<true, false>(B, D); Bt_D_B.template mul<false, false>(Bt_D, B); } } } template <> template <> inline void ShapeLagrange<_ek_regular>::computeBtDB<_point_1>( const Array<Real> & /*Ds*/, Array<Real> & /*BtDBs*/, UInt /*order_d*/, GhostType /*ghost_type*/, const Array<UInt> & /*filter_elements*/) const { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeLagrange<kind>::fieldTimesShapes(const Array<Real> & field, Array<Real> & field_times_shapes, GhostType ghost_type) const { AKANTU_DEBUG_IN(); field_times_shapes.resize(field.size()); UInt size_of_shapes = ElementClass<type>::getShapeSize(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; UInt nb_degree_of_freedom = field.getNbComponent(); const auto & shape = shapes(itp_type, ghost_type); auto field_it = field.begin(nb_degree_of_freedom, 1); auto shapes_it = shape.begin(1, size_of_shapes); auto it = field_times_shapes.begin(nb_degree_of_freedom, size_of_shapes); auto end = field_times_shapes.end(nb_degree_of_freedom, size_of_shapes); for (; it != end; ++it, ++field_it, ++shapes_it) { it->template mul<false, false>(*field_it, *shapes_it); } AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_SHAPE_LAGRANGE_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/shape_structural.cc b/src/fe_engine/shape_structural.cc index cf7315dd2..ef9b443c0 100644 --- a/src/fe_engine/shape_structural.cc +++ b/src/fe_engine/shape_structural.cc @@ -1,53 +1,53 @@ /** * @file shape_structural.cc * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Fri Jul 15 2011 - * @date last modification: Sun Oct 19 2014 + * @date creation: Thu Feb 21 2013 + * @date last modification: Thu Dec 21 2017 * * @brief ShapeStructural implementation * * @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) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "shape_structural.hh" #include "aka_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <> ShapeStructural<_ek_structural>::ShapeStructural(Mesh & mesh, const ID & id, const MemoryID & memory_id) : ShapeFunctions(mesh, id, memory_id), rotation_matrices("rotation_matrices", id, memory_id) {} /* -------------------------------------------------------------------------- */ template <> ShapeStructural<_ek_structural>::~ShapeStructural() = default; /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/fe_engine/shape_structural.hh b/src/fe_engine/shape_structural.hh index bd888aa0e..cefe2841f 100644 --- a/src/fe_engine/shape_structural.hh +++ b/src/fe_engine/shape_structural.hh @@ -1,177 +1,176 @@ /** * @file shape_structural.hh * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Feb 15 2011 - * @date last modification: Thu Oct 22 2015 + * @date last modification: Tue Feb 20 2018 * * @brief shape class for element with different set of shapes functions * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "shape_functions.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_STRUCTURAL_HH__ #define __AKANTU_SHAPE_STRUCTURAL_HH__ namespace akantu { template <ElementKind kind> class ShapeStructural : public ShapeFunctions { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ // Ctors/Dtors should be explicitely implemented for _ek_structural public: ShapeStructural(Mesh & mesh, const ID & id = "shape_structural", const MemoryID & memory_id = 0); ~ShapeStructural() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ShapesStructural [" << std::endl; rotation_matrices.printself(stream, indent + 1); ShapeFunctions::printself(stream, indent + 1); stream << space << "]" << std::endl; } /// compute shape functions on given integration points template <ElementType type> void computeShapesOnIntegrationPoints( const Array<Real> &, const Matrix<Real> & integration_points, Array<Real> & shapes, const GhostType & ghost_type, const Array<UInt> & filter_elements = empty_filter) const; /// initialization function for structural elements inline void initShapeFunctions(const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type); /// precompute the rotation matrices for the elements dofs template <ElementType type> void precomputeRotationMatrices(const Array<Real> & nodes, const GhostType & ghost_type); /// pre compute all shapes on the element integration points from natural /// coordinates template <ElementType type> void precomputeShapesOnIntegrationPoints(const Array<Real> & nodes, const GhostType & ghost_type); /// pre compute all shapes on the element integration points from natural /// coordinates template <ElementType type> void precomputeShapeDerivativesOnIntegrationPoints(const Array<Real> & nodes, const GhostType & ghost_type); /// interpolate nodal values on the integration points template <ElementType type> void interpolateOnIntegrationPoints( const Array<Real> & u, Array<Real> & uq, UInt nb_degree_of_freedom, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; /// compute the gradient of u on the integration points template <ElementType type> void gradientOnIntegrationPoints( const Array<Real> & u, Array<Real> & nablauq, UInt nb_degree_of_freedom, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; /// interpolate on physical point template <ElementType type> void interpolate(const Vector<Real> & /*real_coords*/, UInt /*elem*/, const Matrix<Real> & /*nodal_values*/, Vector<Real> & /*interpolated*/, const GhostType & /*ghost_type*/) const { AKANTU_TO_IMPLEMENT(); } /// compute the shapes on a provided point template <ElementType type> void computeShapes(const Vector<Real> & /*real_coords*/, UInt /*elem*/, Vector<Real> & /*shapes*/, const GhostType & /*ghost_type*/) const { AKANTU_TO_IMPLEMENT(); } /// compute the shape derivatives on a provided point template <ElementType type> void computeShapeDerivatives(const Matrix<Real> & /*real_coords*/, UInt /*elem*/, Tensor3<Real> & /*shapes*/, const GhostType & /*ghost_type*/) const { AKANTU_TO_IMPLEMENT(); } /// multiply a field by shape functions template <ElementType type> void fieldTimesShapes(__attribute__((unused)) const Array<Real> & field, __attribute__((unused)) Array<Real> & field_times_shapes, __attribute__((unused)) const GhostType & ghost_type) const { AKANTU_TO_IMPLEMENT(); } /// get the rotations vector inline const Array<Real> & getRotations(const ElementType & el_type, __attribute__((unused)) const GhostType & ghost_type = _not_ghost) const { return rotation_matrices(el_type); } template <ElementType type> void computeBtD(const Array<Real> & /*Ds*/, Array<Real> & /*BtDs*/, GhostType /*ghost_type*/, const Array<UInt> & /*filter_elements*/) const { AKANTU_TO_IMPLEMENT(); } template <ElementType type> void computeBtDB(const Array<Real> & /*Ds*/, Array<Real> & /*BtDBs*/, UInt /*order_d*/, GhostType /*ghost_type*/, const Array<UInt> & /*filter_elements*/) const { AKANTU_TO_IMPLEMENT(); } protected: ElementTypeMapArray<Real> rotation_matrices; }; } // namespace akantu #include "shape_structural_inline_impl.cc" #endif /* __AKANTU_SHAPE_STRUCTURAL_HH__ */ diff --git a/src/fe_engine/shape_structural_inline_impl.cc b/src/fe_engine/shape_structural_inline_impl.cc index 1919521a3..b13bc8b4d 100644 --- a/src/fe_engine/shape_structural_inline_impl.cc +++ b/src/fe_engine/shape_structural_inline_impl.cc @@ -1,430 +1,431 @@ /** * @file shape_structural_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Mon Dec 13 2010 - * @date last modification: Thu Oct 15 2015 + * @date creation: Wed Oct 11 2017 + * @date last modification: Wed Feb 21 2018 * * @brief ShapeStructural inline implementation * * @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) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "mesh_iterators.hh" #include "shape_structural.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ #define __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ namespace akantu { namespace { /// Extract nodal coordinates per elements template <ElementType type> std::unique_ptr<Array<Real>> getNodesPerElement(const Mesh & mesh, const Array<Real> & nodes, const GhostType & ghost_type) { const auto dim = ElementClass<type>::getSpatialDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nodes_per_element = std::make_unique<Array<Real>>(0, dim * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, *nodes_per_element, type, ghost_type); return nodes_per_element; } } template <ElementKind kind> inline void ShapeStructural<kind>::initShapeFunctions( const Array<Real> & /* unused */, const Matrix<Real> & /* unused */, const ElementType & /* unused */, const GhostType & /* unused */) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ #define INIT_SHAPE_FUNCTIONS(type) \ setIntegrationPointsByType<type>(integration_points, ghost_type); \ precomputeRotationMatrices<type>(nodes, ghost_type); \ precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type); \ precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type); template <> inline void ShapeStructural<_ek_structural>::initShapeFunctions( const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type) { AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS); } #undef INIT_SHAPE_FUNCTIONS /* -------------------------------------------------------------------------- */ template <> template <ElementType type> void ShapeStructural<_ek_structural>::computeShapesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shapes, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { UInt nb_points = integration_points.cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); shapes.resize(nb_element * nb_points); UInt ndof = ElementClass<type>::getNbDegreeOfFreedom(); #if !defined(AKANTU_NDEBUG) UInt size_of_shapes = ElementClass<type>::getShapeSize(); AKANTU_DEBUG_ASSERT(shapes.getNbComponent() == size_of_shapes, "The shapes array does not have the correct " << "number of component"); #endif auto shapes_it = shapes.begin_reinterpret( ElementClass<type>::getNbNodesPerInterpolationElement(), ndof, nb_points, nb_element); auto shapes_begin = shapes_it; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type); auto nodes_it = nodes_per_element->begin(mesh.getSpatialDimension(), Mesh::getNbNodesPerElement(type)); auto nodes_begin = nodes_it; for (UInt elem = 0; elem < nb_element; ++elem) { if (filter_elements != empty_filter) { shapes_it = shapes_begin + filter_elements(elem); nodes_it = nodes_begin + filter_elements(elem); } Tensor3<Real> & N = *shapes_it; auto & real_coord = *nodes_it; ElementClass<type>::computeShapes(integration_points, real_coord, N); if (filter_elements == empty_filter) ++shapes_it; } } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::precomputeRotationMatrices( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const auto spatial_dimension = mesh.getSpatialDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto nb_element = mesh.getNbElement(type, ghost_type); const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom(); if (not this->rotation_matrices.exists(type, ghost_type)) { this->rotation_matrices.alloc(0, nb_dof * nb_dof, type, ghost_type); } auto & rot_matrices = this->rotation_matrices(type, ghost_type); rot_matrices.resize(nb_element); Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type); bool has_extra_normal = mesh.hasData<Real>("extra_normal", type, ghost_type); Array<Real>::const_vector_iterator extra_normal; if (has_extra_normal) extra_normal = mesh.getData<Real>("extra_normal", type, ghost_type) .begin(spatial_dimension); for (auto && tuple : zip(make_view(x_el, spatial_dimension, nb_nodes_per_element), make_view(rot_matrices, nb_dof, nb_dof))) { // compute shape derivatives auto & X = std::get<0>(tuple); auto & R = std::get<1>(tuple); if (has_extra_normal) { ElementClass<type>::computeRotationMatrix(R, X, *extra_normal); ++extra_normal; } else { ElementClass<type>::computeRotationMatrix( R, X, Vector<Real>(spatial_dimension)); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::precomputeShapesOnIntegrationPoints( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const auto & natural_coords = integration_points(type, ghost_type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_points = integration_points(type, ghost_type).cols(); auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom(); const auto dim = ElementClass<type>::getSpatialDimension(); auto itp_type = FEEngine::getInterpolationType(type); if (not shapes.exists(itp_type, ghost_type)) { auto size_of_shapes = this->getShapeSize(type); this->shapes.alloc(0, size_of_shapes, itp_type, ghost_type); } auto & shapes_ = this->shapes(itp_type, ghost_type); shapes_.resize(nb_element * nb_points); auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type); for (auto && tuple : zip(make_view(shapes_, nb_dof, nb_dof * nb_nodes_per_element, nb_points), make_view(*nodes_per_element, dim, nb_nodes_per_element))) { auto & N = std::get<0>(tuple); auto & real_coord = std::get<1>(tuple); ElementClass<type>::computeShapes(natural_coords, real_coord, N); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::precomputeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const auto & natural_coords = integration_points(type, ghost_type); const auto spatial_dimension = mesh.getSpatialDimension(); const auto natural_spatial_dimension = ElementClass<type>::getNaturalSpaceDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto nb_points = natural_coords.cols(); const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom(); const auto nb_element = mesh.getNbElement(type, ghost_type); const auto nb_stress_components = ElementClass<type>::getNbStressComponents(); auto itp_type = FEEngine::getInterpolationType(type); if (not this->shapes_derivatives.exists(itp_type, ghost_type)) { auto size_of_shapesd = this->getShapeDerivativesSize(type); this->shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); } auto & rot_matrices = this->rotation_matrices(type, ghost_type); Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type); auto & shapesd = this->shapes_derivatives(itp_type, ghost_type); shapesd.resize(nb_element * nb_points); for (auto && tuple : zip(make_view(x_el, spatial_dimension, nb_nodes_per_element), make_view(shapesd, nb_stress_components, nb_nodes_per_element * nb_dof, nb_points), make_view(rot_matrices, nb_dof, nb_dof))) { // compute shape derivatives auto & X = std::get<0>(tuple); auto & B = std::get<1>(tuple); auto & RDOFs = std::get<2>(tuple); Tensor3<Real> dnds(natural_spatial_dimension, ElementClass<type>::interpolation_property::dnds_columns, B.size(2)); ElementClass<type>::computeDNDS(natural_coords, X, dnds); Tensor3<Real> J(natural_spatial_dimension, natural_spatial_dimension, natural_coords.cols()); // Computing the coordinates of the element in the natural space auto R = RDOFs.block(0, 0, spatial_dimension, spatial_dimension); Matrix<Real> T(B.size(1), B.size(1), 0); for (UInt i = 0; i < nb_nodes_per_element; ++i) { T.block(RDOFs, i * RDOFs.rows(), i * RDOFs.rows()); } // Rotate to local basis auto x = (R * X).block(0, 0, natural_spatial_dimension, nb_nodes_per_element); ElementClass<type>::computeJMat(natural_coords, x, J); ElementClass<type>::computeShapeDerivatives(J, dnds, T, B); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::interpolateOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_dof, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(out_uq.getNbComponent() == nb_dof, "The output array shape is not correct"); auto itp_type = FEEngine::getInterpolationType(type); const auto & shapes_ = shapes(itp_type, ghost_type); auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement(); auto nb_quad_points_per_element = integration_points(type, ghost_type).cols(); Array<Real> u_el(0, nb_nodes_per_element * nb_dof); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); auto nb_quad_points = nb_quad_points_per_element * u_el.size(); out_uq.resize(nb_quad_points); auto out_it = out_uq.begin_reinterpret(nb_dof, 1, nb_quad_points_per_element, u_el.size()); auto shapes_it = shapes_.begin_reinterpret(nb_dof, nb_dof * nb_nodes_per_element, nb_quad_points_per_element, nb_element); auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1, nb_quad_points_per_element, u_el.size()); for_each_element(nb_element, filter_elements, [&](auto && el) { auto & uq = *out_it; const auto & u = *u_it; auto N = Tensor3<Real>(shapes_it[el]); for (auto && q : arange(uq.size(2))) { auto uq_q = Matrix<Real>(uq(q)); auto u_q = Matrix<Real>(u(q)); auto N_q = Matrix<Real>(N(q)); uq_q.mul<false, false>(N_q, u_q); } ++out_it; ++u_it; }); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::gradientOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_nablauq, UInt nb_dof, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); auto itp_type = FEEngine::getInterpolationType(type); const auto & shapesd = shapes_derivatives(itp_type, ghost_type); auto nb_element = mesh.getNbElement(type, ghost_type); auto element_dimension = ElementClass<type>::getSpatialDimension(); auto nb_quad_points_per_element = integration_points(type, ghost_type).cols(); auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement(); Array<Real> u_el(0, nb_nodes_per_element * nb_dof); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); auto nb_quad_points = nb_quad_points_per_element * u_el.size(); out_nablauq.resize(nb_quad_points); auto out_it = out_nablauq.begin_reinterpret( element_dimension, 1, nb_quad_points_per_element, u_el.size()); auto shapesd_it = shapesd.begin_reinterpret( element_dimension, nb_dof * nb_nodes_per_element, nb_quad_points_per_element, nb_element); auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1, nb_quad_points_per_element, u_el.size()); for_each_element(nb_element, filter_elements, [&](auto && el) { auto & nablau = *out_it; const auto & u = *u_it; auto B = Tensor3<Real>(shapesd_it[el]); for (auto && q : arange(nablau.size(2))) { auto nablau_q = Matrix<Real>(nablau(q)); auto u_q = Matrix<Real>(u(q)); auto B_q = Matrix<Real>(B(q)); nablau_q.mul<false, false>(B_q, u_q); } ++out_it; ++u_it; }); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> template <ElementType type> void ShapeStructural<_ek_structural>::computeBtD( const Array<Real> & Ds, Array<Real> & BtDs, GhostType ghost_type, const Array<UInt> & filter_elements) const { auto itp_type = ElementClassProperty<type>::interpolation_type; auto nb_stress = ElementClass<type>::getNbStressComponents(); auto nb_dof_per_element = ElementClass<type>::getNbDegreeOfFreedom() * mesh.getNbNodesPerElement(type); const auto & shapes_derivatives = this->shapes_derivatives(itp_type, ghost_type); Array<Real> shapes_derivatives_filtered(0, shapes_derivatives.getNbComponent()); auto && view = make_view(shapes_derivatives, nb_stress, nb_dof_per_element); auto B_it = view.begin(); auto B_end = view.end(); if (filter_elements != empty_filter) { FEEngine::filterElementalData(this->mesh, shapes_derivatives, shapes_derivatives_filtered, type, ghost_type, filter_elements); auto && view = make_view(shapes_derivatives_filtered, nb_stress, nb_dof_per_element); B_it = view.begin(); B_end = view.end(); } for (auto && values : zip(range(B_it, B_end), make_view(Ds, nb_stress), make_view(BtDs, BtDs.getNbComponent()))) { const auto & B = std::get<0>(values); const auto & D = std::get<1>(values); auto & Bt_D = std::get<2>(values); Bt_D.template mul<true>(B, D); } } } // namespace akantu #endif /* __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ */ diff --git a/src/geometry/aabb_primitives/aabb_primitive.cc b/src/geometry/aabb_primitives/aabb_primitive.cc index 56b56a7bd..93c51c16b 100644 --- a/src/geometry/aabb_primitives/aabb_primitive.cc +++ b/src/geometry/aabb_primitives/aabb_primitive.cc @@ -1,49 +1,49 @@ /** * @file aabb_primitive.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Macro classe (primitive) for AABB CGAL algos * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aabb_primitive.hh" namespace akantu { Triangle_primitive::Point Triangle_primitive::reference_point() const { return primitive.vertex(0); } Line_arc_primitive::Point Line_arc_primitive::reference_point() const { Real x = to_double(primitive.source().x()); Real y = to_double(primitive.source().y()); Real z = to_double(primitive.source().z()); return cgal::Spherical::Point_3(x, y, z); } } // akantu diff --git a/src/geometry/aabb_primitives/aabb_primitive.hh b/src/geometry/aabb_primitives/aabb_primitive.hh index af9ac05f4..9bae09a10 100644 --- a/src/geometry/aabb_primitives/aabb_primitive.hh +++ b/src/geometry/aabb_primitives/aabb_primitive.hh @@ -1,89 +1,89 @@ /** * @file aabb_primitive.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * * @date creation: Fri Mar 13 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Macro classe (primitive) for AABB CGAL algos * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AABB_PRIMITIVE_HH__ #define __AKANTU_AABB_PRIMITIVE_HH__ #include "aka_common.hh" #include "line_arc.hh" #include "tetrahedron.hh" #include "triangle.hh" #include "mesh_geom_common.hh" namespace akantu { /** * This macro defines a class that is used in the CGAL AABB tree algorithm. * All the `typedef`s and methods are required by the AABB module. * * The member variables are * - the id of the element associated to the primitive * - the geometric primitive of the element * * @param name the name of the primitive type * @param kernel the name of the kernel used */ #define AKANTU_AABB_CLASS(name, kernel) \ class name##_primitive { \ typedef std::list<name<kernel>>::iterator Iterator; \ \ public: \ typedef UInt Id; \ typedef kernel::Point_3 Point; \ typedef kernel::name##_3 Datum; \ \ public: \ name##_primitive() : meshId(0), primitive() {} \ name##_primitive(Iterator it) : meshId(it->id()), primitive(*it) {} \ \ public: \ const Datum & datum() const { return primitive; } \ Point reference_point() const; \ const Id & id() const { return meshId; } \ \ protected: \ Id meshId; \ name<kernel> primitive; \ } // If the primitive is supported by CGAL::intersection() then the // implementation process is really easy with this macro AKANTU_AABB_CLASS(Triangle, cgal::Cartesian); AKANTU_AABB_CLASS(Line_arc, cgal::Spherical); #undef AKANTU_AABB_CLASS } // akantu #endif // __AKANTU_AABB_PRIMITIVE_HH__ diff --git a/src/geometry/aabb_primitives/line_arc.hh b/src/geometry/aabb_primitives/line_arc.hh index 603525067..611649790 100644 --- a/src/geometry/aabb_primitives/line_arc.hh +++ b/src/geometry/aabb_primitives/line_arc.hh @@ -1,77 +1,77 @@ /** * @file line_arc.hh * * @author Clement Roux <clement.roux@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief Segment classe (geometry) for AABB CGAL algos * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_LINE_ARC_HH__ #define __AKANTU_LINE_ARC_HH__ #include "aka_common.hh" #include "mesh_geom_common.hh" namespace akantu { /* -------------------------------------------------------------------------- */ /// Class used for substitution of CGAL::Triangle_3 primitive template <typename K> class Line_arc : public CGAL::Line_arc_3<K> { public: /// Default constructor Line_arc() : CGAL::Line_arc_3<K>(), mesh_id(0), seg_id(0) {} /// Copy constructor Line_arc(const Line_arc & other) : CGAL::Line_arc_3<K>(other), mesh_id(other.mesh_id), seg_id(other.seg_id) {} /// Construct from 3 points // "CGAL-4.5/doc_html/Circular_kernel_3/classCGAL_1_1Line__arc__3.html" Line_arc(const CGAL::Line_3<K> & l, const CGAL::Circular_arc_point_3<K> & a, const CGAL::Circular_arc_point_3<K> & b) : CGAL::Line_arc_3<K>(l, a, b), mesh_id(0), seg_id(0) {} public: UInt id() const { return mesh_id; } UInt segId() const { return seg_id; } void setId(UInt newId) { mesh_id = newId; } void setSegId(UInt newId) { seg_id = newId; } protected: /// Id of the element represented by the primitive UInt mesh_id; /// Id of the segment represented by the primitive UInt seg_id; }; } // akantu #endif // __AKANTU_LINE_ARC_HH__ diff --git a/src/geometry/aabb_primitives/tetrahedron.hh b/src/geometry/aabb_primitives/tetrahedron.hh index c6d31b3de..64e7855a7 100644 --- a/src/geometry/aabb_primitives/tetrahedron.hh +++ b/src/geometry/aabb_primitives/tetrahedron.hh @@ -1,70 +1,70 @@ /** * @file tetrahedron.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Feb 27 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief Tetrahedron classe (geometry) for AABB CGAL algos * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TETRAHEDRON_HH__ #define __AKANTU_TETRAHEDRON_HH__ #include "aka_common.hh" #include "mesh_geom_common.hh" namespace akantu { /* -------------------------------------------------------------------------- */ /// Class used for substitution of CGAL::Tetrahedron_3 primitive template <typename K> class Tetrahedron : public CGAL::Tetrahedron_3<K> { public: /// Default constructor Tetrahedron() : CGAL::Tetrahedron_3<K>(), meshId(0) {} /// Copy constructor Tetrahedron(const Tetrahedron & other) : CGAL::Tetrahedron_3<K>(other), meshId(other.meshId) {} /// Construct from 4 points Tetrahedron(const CGAL::Point_3<K> & a, const CGAL::Point_3<K> & b, const CGAL::Point_3<K> & c, const CGAL::Point_3<K> & d) : CGAL::Tetrahedron_3<K>(a, b, c, d), meshId(0) {} public: UInt id() const { return meshId; } void setId(UInt newId) { meshId = newId; } protected: /// Id of the element represented by the primitive UInt meshId; }; } // akantu #endif diff --git a/src/geometry/aabb_primitives/triangle.hh b/src/geometry/aabb_primitives/triangle.hh index 90a36b4bd..17d7b194a 100644 --- a/src/geometry/aabb_primitives/triangle.hh +++ b/src/geometry/aabb_primitives/triangle.hh @@ -1,70 +1,70 @@ /** * @file triangle.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief Triangle classe (geometry) for AABB CGAL algos * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TRIANGLE_HH__ #define __AKANTU_TRIANGLE_HH__ #include "aka_common.hh" #include "mesh_geom_common.hh" namespace akantu { /* -------------------------------------------------------------------------- */ /// Class used for substitution of CGAL::Triangle_3 primitive template <typename K> class Triangle : public CGAL::Triangle_3<K> { public: /// Default constructor Triangle() : CGAL::Triangle_3<K>(), meshId(0) {} /// Copy constructor Triangle(const Triangle & other) : CGAL::Triangle_3<K>(other), meshId(other.meshId) {} /// Construct from 3 points Triangle(const CGAL::Point_3<K> & a, const CGAL::Point_3<K> & b, const CGAL::Point_3<K> & c) : CGAL::Triangle_3<K>(a, b, c), meshId(0) {} public: UInt id() const { return meshId; } void setId(UInt newId) { meshId = newId; } protected: /// Id of the element represented by the primitive UInt meshId; }; } // akantu #endif // __AKANTU_TRIANGLE_HH__ diff --git a/src/geometry/geom_helper_functions.hh b/src/geometry/geom_helper_functions.hh index 0d68d20e2..f3cc29d22 100644 --- a/src/geometry/geom_helper_functions.hh +++ b/src/geometry/geom_helper_functions.hh @@ -1,112 +1,112 @@ /** * @file geom_helper_functions.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Helper functions for the computational geometry algorithms * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef _AKANTU_GEOM_HELPER_FUNCTIONS_HH__ #define _AKANTU_GEOM_HELPER_FUNCTIONS_HH__ #include "aka_common.hh" #include "aka_math.hh" #include "tree_type_helper.hh" #include "mesh_geom_common.hh" namespace akantu { /// Fuzzy compare of two points template <class Point> inline bool comparePoints(const Point & a, const Point & b) { return Math::are_float_equal(a.x(), b.x()) && Math::are_float_equal(a.y(), b.y()) && Math::are_float_equal(a.z(), b.z()); } template <> inline bool comparePoints(const cgal::Spherical::Circular_arc_point_3 & a, const cgal::Spherical::Circular_arc_point_3 & b) { return Math::are_float_equal(CGAL::to_double(a.x()), CGAL::to_double(b.x())) && Math::are_float_equal(CGAL::to_double(a.y()), CGAL::to_double(b.y())) && Math::are_float_equal(CGAL::to_double(a.z()), CGAL::to_double(b.z())); } /// Fuzzy compare of two segments template <class K> inline bool compareSegments(const CGAL::Segment_3<K> & a, const CGAL::Segment_3<K> & b) { return (comparePoints(a.source(), b.source()) && comparePoints(a.target(), b.target())) || (comparePoints(a.source(), b.target()) && comparePoints(a.target(), b.source())); } /// Compare segment pairs inline bool compareSegmentPairs(const std::pair<cgal::Cartesian::Segment_3, UInt> & a, const std::pair<cgal::Cartesian::Segment_3, UInt> & b) { return compareSegments(a.first, b.first); } /// Pair ordering operator based on first member struct segmentPairsLess { inline bool operator()(const std::pair<cgal::Cartesian::Segment_3, UInt> & a, const std::pair<cgal::Cartesian::Segment_3, UInt> & b) { return CGAL::compare_lexicographically(a.first.min(), b.first.min()) || CGAL::compare_lexicographically(a.first.max(), b.first.max()); } }; /* -------------------------------------------------------------------------- */ /* Predicates */ /* -------------------------------------------------------------------------- */ /// Predicate used to determine if two segments are equal class IsSameSegment { public: IsSameSegment(const cgal::Cartesian::Segment_3 & segment) : segment(segment) {} bool operator()(const std::pair<cgal::Cartesian::Segment_3, UInt> & test_pair) { return compareSegments(segment, test_pair.first); } protected: const cgal::Cartesian::Segment_3 segment; }; } // akantu #endif // _AKANTU_GEOM_HELPER_FUNCTIONS_HH__ diff --git a/src/geometry/mesh_abstract_intersector.hh b/src/geometry/mesh_abstract_intersector.hh index 5467a673b..2bf1c1b29 100644 --- a/src/geometry/mesh_abstract_intersector.hh +++ b/src/geometry/mesh_abstract_intersector.hh @@ -1,121 +1,121 @@ /** * @file mesh_abstract_intersector.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Apr 29 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief Abstract class for intersection computations * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_ABSTRACT_INTERSECTOR_HH__ #define __AKANTU_MESH_ABSTRACT_INTERSECTOR_HH__ #include "aka_common.hh" #include "mesh_geom_abstract.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /** * @brief Class used to perform intersections on a mesh and construct output * data */ template <class Query> class MeshAbstractIntersector : public MeshGeomAbstract { public: /// Construct from mesh explicit MeshAbstractIntersector(Mesh & mesh); /// Destructor virtual ~MeshAbstractIntersector(); public: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the new_node_per_elem array AKANTU_GET_MACRO(NewNodePerElem, *new_node_per_elem, const Array<UInt> &); /// get the intersection_points array AKANTU_GET_MACRO(IntersectionPoints, intersection_points, const Array<Real> *); /// get the nb_seg_by_el UInt AKANTU_GET_MACRO(NbSegByEl, nb_seg_by_el, UInt); /** * @brief Compute the intersection with a query object * * This function needs to be implemented for every subclass. It computes the * intersections * with the tree of primitives and creates the data for the user. * * @param query the CGAL primitive of the query object */ virtual void computeIntersectionQuery(const Query & query) = 0; /// Compute intersection points between the mesh primitives (segments) and a /// query (surface in 3D or a curve in 2D), double intersection points for the /// same primitives are not considered. A maximum intersection node per /// element is set : 2 in 2D and 4 in 3D virtual void computeMeshQueryIntersectionPoint(const Query & query, UInt nb_old_nodes) = 0; /// Compute intersection between the mesh and a list of queries virtual void computeIntersectionQueryList(const std::list<Query> & query_list); /// Compute intersection points between the mesh and a list of queries virtual void computeMeshQueryListIntersectionPoint(const std::list<Query> & query_list, UInt nb_old_nodes); /// Compute whatever result is needed from the user (should be move to the /// appropriate specific classe for genericity) virtual void buildResultFromQueryList(const std::list<Query> & query_list) = 0; protected: /// new node per element (column 0: number of new nodes, then odd is the /// intersection node number and even the ID of the intersected segment) Array<UInt> * new_node_per_elem; /// intersection output: new intersection points /// (computeMeshQueryListIntersectionPoint) Array<Real> * intersection_points; /// number of segment in a considered element of the templated type of element /// specialized intersector const UInt nb_seg_by_el; }; } // akantu #include "mesh_abstract_intersector_tmpl.hh" #endif // __AKANTU_MESH_ABSTRACT_INTERSECTOR_HH__ diff --git a/src/geometry/mesh_abstract_intersector_tmpl.hh b/src/geometry/mesh_abstract_intersector_tmpl.hh index 8ed2a1da4..ccd833882 100644 --- a/src/geometry/mesh_abstract_intersector_tmpl.hh +++ b/src/geometry/mesh_abstract_intersector_tmpl.hh @@ -1,83 +1,83 @@ /** * @file mesh_abstract_intersector_tmpl.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Apr 29 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief General class for intersection computations * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_ABSTRACT_INTERSECTOR_TMPL_HH__ #define __AKANTU_MESH_ABSTRACT_INTERSECTOR_TMPL_HH__ #include "aka_common.hh" #include "mesh_abstract_intersector.hh" namespace akantu { template <class Query> MeshAbstractIntersector<Query>::MeshAbstractIntersector(Mesh & mesh) : MeshGeomAbstract(mesh), new_node_per_elem(NULL), intersection_points(NULL), nb_seg_by_el(0) {} template <class Query> MeshAbstractIntersector<Query>::~MeshAbstractIntersector() {} template <class Query> void MeshAbstractIntersector<Query>::computeIntersectionQueryList( const std::list<Query> & query_list) { AKANTU_DEBUG_IN(); typename std::list<Query>::const_iterator query_it = query_list.begin(), query_end = query_list.end(); for (; query_it != query_end; ++query_it) { computeIntersectionQuery(*query_it); } AKANTU_DEBUG_OUT(); } template <class Query> void MeshAbstractIntersector<Query>::computeMeshQueryListIntersectionPoint( const std::list<Query> & query_list, UInt nb_old_nodes) { AKANTU_DEBUG_IN(); typename std::list<Query>::const_iterator query_it = query_list.begin(), query_end = query_list.end(); for (; query_it != query_end; ++query_it) { computeMeshQueryIntersectionPoint(*query_it, nb_old_nodes); } AKANTU_DEBUG_OUT(); } } // akantu #endif // __AKANTU_MESH_ABSTRACT_INTERSECTOR_TMPL_HH__ diff --git a/src/geometry/mesh_geom_abstract.hh b/src/geometry/mesh_geom_abstract.hh index 8805f7050..530924b48 100644 --- a/src/geometry/mesh_geom_abstract.hh +++ b/src/geometry/mesh_geom_abstract.hh @@ -1,65 +1,65 @@ /** * @file mesh_geom_abstract.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief Class for constructing the CGAL primitives of a mesh * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_GEOM_ABSTRACT_HH__ #define __AKANTU_MESH_GEOM_ABSTRACT_HH__ #include "aka_common.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /// Abstract class for mesh geometry operations class MeshGeomAbstract { public: /// Construct from mesh explicit MeshGeomAbstract(Mesh & mesh) : mesh(mesh){}; /// Destructor virtual ~MeshGeomAbstract(){}; public: /// Construct geometric data for computational geometry algorithms virtual void constructData(GhostType ghost_type = _not_ghost) = 0; protected: /// Mesh used to construct the primitives Mesh & mesh; }; } // akantu #endif // __AKANTU_MESH_GEOM_ABSTRACT_HH__ diff --git a/src/geometry/mesh_geom_common.hh b/src/geometry/mesh_geom_common.hh index ccc6f8d8b..528e965a8 100644 --- a/src/geometry/mesh_geom_common.hh +++ b/src/geometry/mesh_geom_common.hh @@ -1,57 +1,57 @@ /** * @file mesh_geom_common.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Common file for MeshGeom module * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_MESH_GEOM_COMMON_HH__ #define __AKANTU_MESH_GEOM_COMMON_HH__ #include "aka_common.hh" #include <CGAL/MP_Float.h> #include <CGAL/Quotient.h> #include <CGAL/Algebraic_kernel_for_spheres_2_3.h> #include <CGAL/Cartesian.h> #include <CGAL/Simple_cartesian.h> #include <CGAL/Spherical_kernel_3.h> namespace akantu { namespace cgal { using Cartesian = CGAL::Simple_cartesian<Real>; using Spherical = CGAL::Spherical_kernel_3< CGAL::Simple_cartesian<CGAL::Quotient<CGAL::MP_Float>>, CGAL::Algebraic_kernel_for_spheres_2_3<CGAL::Quotient<CGAL::MP_Float>>>; } // cgal } // akantu #endif // __AKANTU_MESH_GEOM_COMMON_HH__ diff --git a/src/geometry/mesh_geom_factory.hh b/src/geometry/mesh_geom_factory.hh index 68f1b927b..1b31ea553 100644 --- a/src/geometry/mesh_geom_factory.hh +++ b/src/geometry/mesh_geom_factory.hh @@ -1,107 +1,107 @@ /** * @file mesh_geom_factory.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Feb 27 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief Class for constructing the CGAL primitives of a mesh * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_GEOM_FACTORY_HH__ #define __AKANTU_MESH_GEOM_FACTORY_HH__ #include "aka_common.hh" #include "geom_helper_functions.hh" #include "mesh.hh" #include "mesh_geom_abstract.hh" #include "tree_type_helper.hh" #include <algorithm> /* -------------------------------------------------------------------------- */ namespace akantu { /** * @brief Class used to construct AABB tree for intersection computations * * This class constructs a CGAL AABB tree of one type of element in a mesh * for fast intersection computations. */ template <UInt dim, ElementType el_type, class Primitive, class Kernel> class MeshGeomFactory : public MeshGeomAbstract { public: /// Construct from mesh explicit MeshGeomFactory(Mesh & mesh); /// Desctructor virtual ~MeshGeomFactory(); public: /// Construct AABB tree for fast intersection computing virtual void constructData(GhostType ghost_type = _not_ghost); /** * @brief Construct a primitive and add it to a list of primitives * * This function needs to be specialized for every type that is wished to be * supported. * @param node_coordinates coordinates of the nodes making up the element * @param id element number * @param list the primitive list (not used inside MeshGeomFactory) */ inline void addPrimitive( const Matrix<Real> & node_coordinates, UInt id, typename TreeTypeHelper<Primitive, Kernel>::container_type & list); inline void addPrimitive(const Matrix<Real> & node_coordinates, UInt id); /// Getter for the AABB tree const typename TreeTypeHelper<Primitive, Kernel>::tree & getTree() const { return *data_tree; } /// Getter for primitive list const typename TreeTypeHelper<Primitive, Kernel>::container_type & getPrimitiveList() const { return primitive_list; } protected: /// AABB data tree typename TreeTypeHelper<Primitive, Kernel>::tree * data_tree; /// Primitive list typename TreeTypeHelper<Primitive, Kernel>::container_type primitive_list; }; } // akantu #include "mesh_geom_factory_tmpl.hh" #endif // __AKANTU_MESH_GEOM_FACTORY_HH__ diff --git a/src/geometry/mesh_geom_factory_tmpl.hh b/src/geometry/mesh_geom_factory_tmpl.hh index 5caf3048b..a7028a652 100644 --- a/src/geometry/mesh_geom_factory_tmpl.hh +++ b/src/geometry/mesh_geom_factory_tmpl.hh @@ -1,271 +1,271 @@ /** * @file mesh_geom_factory_tmpl.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Feb 27 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Class for constructing the CGAL primitives of a mesh * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ #define __AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh_geom_common.hh" #include "mesh_geom_factory.hh" /* -------------------------------------------------------------------------- */ namespace akantu { template <UInt dim, ElementType type, class Primitive, class Kernel> MeshGeomFactory<dim, type, Primitive, Kernel>::MeshGeomFactory(Mesh & mesh) : MeshGeomAbstract(mesh), data_tree(NULL), primitive_list() {} template <UInt dim, ElementType type, class Primitive, class Kernel> MeshGeomFactory<dim, type, Primitive, Kernel>::~MeshGeomFactory() { delete data_tree; } /** * This function loops over the elements of `type` in the mesh and creates the * AABB tree of geometrical primitves (`data_tree`). */ template <UInt dim, ElementType type, class Primitive, class Kernel> void MeshGeomFactory<dim, type, Primitive, Kernel>::constructData( GhostType ghost_type) { AKANTU_DEBUG_IN(); primitive_list.clear(); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); const Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); const Array<Real> & nodes = mesh.getNodes(); UInt el_index = 0; Array<UInt>::const_vector_iterator it = connectivity.begin(nb_nodes_per_element); Array<UInt>::const_vector_iterator end = connectivity.end(nb_nodes_per_element); Matrix<Real> node_coordinates(dim, nb_nodes_per_element); // This loop builds the list of primitives for (; it != end; ++it, ++el_index) { const Vector<UInt> & el_connectivity = *it; for (UInt i = 0; i < nb_nodes_per_element; i++) for (UInt j = 0; j < dim; j++) node_coordinates(j, i) = nodes(el_connectivity(i), j); // the unique elemental id assigned to the primitive is the // linearized element index over ghost type addPrimitive(node_coordinates, el_index); } delete data_tree; // This condition allows the use of the mesh geom module // even if types are not compatible with AABB tree algorithm if (TreeTypeHelper<Primitive, Kernel>::is_valid) data_tree = new typename TreeTypeHelper<Primitive, Kernel>::tree( primitive_list.begin(), primitive_list.end()); AKANTU_DEBUG_OUT(); } template <UInt dim, ElementType type, class Primitive, class Kernel> void MeshGeomFactory<dim, type, Primitive, Kernel>::addPrimitive( const Matrix<Real> & node_coordinates, UInt id) { this->addPrimitive(node_coordinates, id, this->primitive_list); } // (2D, _triangle_3) decomposed into Triangle<cgal::Cartesian> template <> inline void MeshGeomFactory<2, _triangle_3, Triangle<cgal::Cartesian>, cgal::Cartesian>:: addPrimitive(const Matrix<Real> & node_coordinates, UInt id, TreeTypeHelper<Triangle<cgal::Cartesian>, cgal::Cartesian>::container_type & list) { TreeTypeHelper<Triangle<cgal::Cartesian>, cgal::Cartesian>::point_type a( node_coordinates(0, 0), node_coordinates(1, 0), 0.), b(node_coordinates(0, 1), node_coordinates(1, 1), 0.), c(node_coordinates(0, 2), node_coordinates(1, 2), 0.); Triangle<cgal::Cartesian> t(a, b, c); t.setId(id); list.push_back(t); } // (2D, _triangle_6) decomposed into Triangle<cgal::Cartesian> template <> inline void MeshGeomFactory<2, _triangle_6, Triangle<cgal::Cartesian>, cgal::Cartesian>:: addPrimitive(const Matrix<Real> & node_coordinates, UInt id, TreeTypeHelper<Triangle<cgal::Cartesian>, cgal::Cartesian>::container_type & list) { TreeTypeHelper<Triangle<cgal::Cartesian>, cgal::Cartesian>::point_type a( node_coordinates(0, 0), node_coordinates(1, 0), 0.), b(node_coordinates(0, 1), node_coordinates(1, 1), 0.), c(node_coordinates(0, 2), node_coordinates(1, 2), 0.); Triangle<cgal::Cartesian> t(a, b, c); t.setId(id); list.push_back(t); } // (2D, _triangle_3) decomposed into Line_arc<cgal::Spherical> template <> inline void MeshGeomFactory<2, _triangle_3, Line_arc<cgal::Spherical>, cgal::Spherical>:: addPrimitive(const Matrix<Real> & node_coordinates, UInt id, TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::container_type & list) { TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::point_type a( node_coordinates(0, 0), node_coordinates(1, 0), 0.), b(node_coordinates(0, 1), node_coordinates(1, 1), 0.), c(node_coordinates(0, 2), node_coordinates(1, 2), 0.); /*std::cout << "elem " << id << " node 1 : x_node=" << node_coordinates(0, 0) << ", x_arc_node=" << a.x() << ", y_node=" << node_coordinates(1, 0) << ", y_arc_node=" << a.y() << std::endl ; std::cout << "elem " << id << " node 2 : x_node=" << node_coordinates(0, 1) << ", x_arc_node=" << b.x() << ", y_node=" << node_coordinates(1, 1) << ", y_arc_node=" << b.y() << std::endl ; std::cout << "elem " << id << " node 2 : x_node=" << node_coordinates(0, 2) << ", x_arc_node=" << c.x() << ", y_node=" << node_coordinates(1, 2) << ", y_arc_node=" << c.y() << std::endl ;*/ CGAL::Line_3<cgal::Spherical> l1(a, b), l2(b, c), l3(c, a); Line_arc<cgal::Spherical> s1(l1, a, b), s2(l2, b, c), s3(l3, c, a); s1.setId(id); s1.setSegId(0); s2.setId(id); s2.setSegId(1); s3.setId(id); s3.setSegId(2); list.push_back(s1); list.push_back(s2); list.push_back(s3); } #if defined(AKANTU_IGFEM) // (2D, _igfem_triangle_4) decomposed into Line_arc<cgal::Spherical> template <> inline void MeshGeomFactory<2, _igfem_triangle_4, Line_arc<cgal::Spherical>, cgal::Spherical>:: addPrimitive(const Matrix<Real> & node_coordinates, UInt id, TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::container_type & list) { TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::point_type a( node_coordinates(0, 0), node_coordinates(1, 0), 0.), b(node_coordinates(0, 1), node_coordinates(1, 1), 0.), c(node_coordinates(0, 2), node_coordinates(1, 2), 0.); CGAL::Line_3<cgal::Spherical> l1(a, b), l2(b, c), l3(c, a); Line_arc<cgal::Spherical> s1(l1, a, b), s2(l2, b, c), s3(l3, c, a); s1.setId(id); s1.setSegId(0); s2.setId(id); s2.setSegId(1); s3.setId(id); s3.setSegId(2); list.push_back(s1); list.push_back(s2); list.push_back(s3); } // (2D, _igfem_triangle_4) decomposed into Line_arc<cgal::Spherical> template <> inline void MeshGeomFactory<2, _igfem_triangle_5, Line_arc<cgal::Spherical>, cgal::Spherical>:: addPrimitive(const Matrix<Real> & node_coordinates, UInt id, TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::container_type & list) { TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::point_type a( node_coordinates(0, 0), node_coordinates(1, 0), 0.), b(node_coordinates(0, 1), node_coordinates(1, 1), 0.), c(node_coordinates(0, 2), node_coordinates(1, 2), 0.); CGAL::Line_3<cgal::Spherical> l1(a, b), l2(b, c), l3(c, a); Line_arc<cgal::Spherical> s1(l1, a, b), s2(l2, b, c), s3(l3, c, a); s1.setId(id); s1.setSegId(0); s2.setId(id); s2.setSegId(1); s3.setId(id); s3.setSegId(2); list.push_back(s1); list.push_back(s2); list.push_back(s3); } #endif // (3D, _tetrahedron_4) decomposed into Triangle<cgal::Cartesian> template <> inline void MeshGeomFactory<3, _tetrahedron_4, Triangle<cgal::Cartesian>, cgal::Cartesian>:: addPrimitive(const Matrix<Real> & node_coordinates, UInt id, TreeTypeHelper<Triangle<cgal::Cartesian>, cgal::Cartesian>::container_type & list) { TreeTypeHelper<Triangle<cgal::Cartesian>, cgal::Cartesian>::point_type a( node_coordinates(0, 0), node_coordinates(1, 0), node_coordinates(2, 0)), b(node_coordinates(0, 1), node_coordinates(1, 1), node_coordinates(2, 1)), c(node_coordinates(0, 2), node_coordinates(1, 2), node_coordinates(2, 2)), d(node_coordinates(0, 3), node_coordinates(1, 3), node_coordinates(2, 3)); Triangle<cgal::Cartesian> t1(a, b, c), t2(b, c, d), t3(c, d, a), t4(d, a, b); t1.setId(id); t2.setId(id); t3.setId(id); t4.setId(id); list.push_back(t1); list.push_back(t2); list.push_back(t3); list.push_back(t4); } } // akantu #endif // __AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ diff --git a/src/geometry/mesh_geom_intersector.hh b/src/geometry/mesh_geom_intersector.hh index d8552c6f3..a0082b077 100644 --- a/src/geometry/mesh_geom_intersector.hh +++ b/src/geometry/mesh_geom_intersector.hh @@ -1,74 +1,74 @@ /** * @file mesh_geom_intersector.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Apr 29 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief General class for intersection computations * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_GEOM_INTERSECTOR_HH__ #define __AKANTU_MESH_GEOM_INTERSECTOR_HH__ #include "aka_common.hh" #include "mesh_abstract_intersector.hh" #include "mesh_geom_factory.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /** * @brief Class used to perform intersections on a mesh and construct output * data */ template <UInt dim, ElementType type, class Primitive, class Query, class Kernel> class MeshGeomIntersector : public MeshAbstractIntersector<Query> { public: /// Construct from mesh explicit MeshGeomIntersector(Mesh & mesh); /// Destructor virtual ~MeshGeomIntersector(); public: /// Construct the primitive tree object virtual void constructData(GhostType ghost_type = _not_ghost); protected: /// Factory object containing the primitive tree MeshGeomFactory<dim, type, Primitive, Kernel> factory; }; } // akantu #include "mesh_geom_intersector_tmpl.hh" #endif // __AKANTU_MESH_GEOM_INTERSECTOR_HH__ diff --git a/src/geometry/mesh_geom_intersector_tmpl.hh b/src/geometry/mesh_geom_intersector_tmpl.hh index 0e2ab5bb9..7bedae20d 100644 --- a/src/geometry/mesh_geom_intersector_tmpl.hh +++ b/src/geometry/mesh_geom_intersector_tmpl.hh @@ -1,64 +1,64 @@ /** * @file mesh_geom_intersector_tmpl.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Wed Apr 29 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Jun 19 2017 * * @brief General class for intersection computations * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_GEOM_INTERSECTOR_TMPL_HH__ #define __AKANTU_MESH_GEOM_INTERSECTOR_TMPL_HH__ #include "aka_common.hh" #include "mesh_geom_intersector.hh" /* -------------------------------------------------------------------------- */ namespace akantu { template <UInt dim, ElementType type, class Primitive, class Query, class Kernel> MeshGeomIntersector<dim, type, Primitive, Query, Kernel>::MeshGeomIntersector( Mesh & mesh) : MeshAbstractIntersector<Query>(mesh), factory(mesh) {} template <UInt dim, ElementType type, class Primitive, class Query, class Kernel> MeshGeomIntersector<dim, type, Primitive, Query, Kernel>::~MeshGeomIntersector() {} template <UInt dim, ElementType type, class Primitive, class Query, class Kernel> void MeshGeomIntersector<dim, type, Primitive, Query, Kernel>::constructData( GhostType ghost_type) { this->intersection_points->resize(0); factory.constructData(ghost_type); } } // akantu #endif // __AKANTU_MESH_GEOM_INTERSECTOR_TMPL_HH__ diff --git a/src/geometry/mesh_segment_intersector.hh b/src/geometry/mesh_segment_intersector.hh index 6e7c38e2d..b6691c10b 100644 --- a/src/geometry/mesh_segment_intersector.hh +++ b/src/geometry/mesh_segment_intersector.hh @@ -1,109 +1,109 @@ /** * @file mesh_segment_intersector.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Apr 29 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Computation of mesh intersection with segments * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_SEGMENT_INTERSECTOR_HH__ #define __AKANTU_MESH_SEGMENT_INTERSECTOR_HH__ #include "aka_common.hh" #include "mesh_geom_intersector.hh" #include "mesh_geom_common.hh" /* -------------------------------------------------------------------------- */ namespace akantu { template <UInt dim, ElementType type> class MeshSegmentIntersector : public MeshGeomIntersector<dim, type, Triangle<cgal::Cartesian>, cgal::Cartesian::Segment_3, cgal::Cartesian> { using K = cgal::Cartesian; /// Parent class type typedef MeshGeomIntersector<dim, type, Triangle<K>, K::Segment_3, K> parent_type; /// Result of intersection function type typedef typename IntersectionTypeHelper<TreeTypeHelper<Triangle<K>, K>, K::Segment_3>::intersection_type result_type; /// Pair of segments and element id typedef std::pair<K::Segment_3, UInt> pair_type; public: /// Construct from mesh explicit MeshSegmentIntersector(Mesh & mesh, Mesh & result_mesh); /// Destructor virtual ~MeshSegmentIntersector(); public: /** * @brief Computes the intersection of the mesh with a segment * * @param query the segment to compute the intersections with the mesh */ virtual void computeIntersectionQuery(const K::Segment_3 & query); /// Compute intersection points between the mesh and a query virtual void computeMeshQueryIntersectionPoint(const K::Segment_3 & query, UInt nb_old_nodes); /// Compute the embedded mesh virtual void buildResultFromQueryList(const std::list<K::Segment_3> & query_list); void setPhysicalName(const std::string & other) { current_physical_name = other; } protected: /// Compute segments from intersection list void computeSegments(const std::list<result_type> & intersections, std::set<pair_type, segmentPairsLess> & segments, const K::Segment_3 & query); protected: /// Result mesh Mesh & result_mesh; /// Physical name of the current batch of queries std::string current_physical_name; }; } // akantu #include "mesh_segment_intersector_tmpl.hh" #endif // __AKANTU_MESH_SEGMENT_INTERSECTOR_HH__ diff --git a/src/geometry/mesh_segment_intersector_tmpl.hh b/src/geometry/mesh_segment_intersector_tmpl.hh index 92538a104..80f75640f 100644 --- a/src/geometry/mesh_segment_intersector_tmpl.hh +++ b/src/geometry/mesh_segment_intersector_tmpl.hh @@ -1,283 +1,283 @@ /** * @file mesh_segment_intersector_tmpl.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Apr 29 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Computation of mesh intersection with segments * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_SEGMENT_INTERSECTOR_TMPL_HH__ #define __AKANTU_MESH_SEGMENT_INTERSECTOR_TMPL_HH__ #include "aka_common.hh" #include "mesh_geom_common.hh" #include "tree_type_helper.hh" namespace akantu { template <UInt dim, ElementType type> MeshSegmentIntersector<dim, type>::MeshSegmentIntersector(Mesh & mesh, Mesh & result_mesh) : parent_type(mesh), result_mesh(result_mesh), current_physical_name() { this->intersection_points = new Array<Real>(0, dim); this->constructData(); } template <UInt dim, ElementType type> MeshSegmentIntersector<dim, type>::~MeshSegmentIntersector() {} template <UInt dim, ElementType type> void MeshSegmentIntersector<dim, type>::computeIntersectionQuery( const K::Segment_3 & query) { AKANTU_DEBUG_IN(); result_mesh.addConnectivityType(_segment_2, _not_ghost); result_mesh.addConnectivityType(_segment_2, _ghost); std::list<result_type> result_list; std::set<std::pair<K::Segment_3, UInt>, segmentPairsLess> segment_set; this->factory.getTree().all_intersections(query, std::back_inserter(result_list)); this->computeSegments(result_list, segment_set, query); // Arrays for storing nodes and connectivity Array<Real> & nodes = result_mesh.getNodes(); Array<UInt> & connectivity = result_mesh.getConnectivity(_segment_2); // Arrays for storing associated element and physical name bool valid_elemental_data = true; Array<Element> * associated_element = NULL; Array<std::string> * associated_physical_name = NULL; try { associated_element = &result_mesh.getData<Element>("associated_element", _segment_2); associated_physical_name = &result_mesh.getData<std::string>("physical_names", _segment_2); } catch (debug::Exception & e) { valid_elemental_data = false; } std::set<pair_type, segmentPairsLess>::iterator it = segment_set.begin(), end = segment_set.end(); // Loop over the segment pairs for (; it != end; ++it) { if (!it->first.is_degenerate()) { Vector<UInt> segment_connectivity(2); segment_connectivity(0) = result_mesh.getNbNodes(); segment_connectivity(1) = result_mesh.getNbNodes() + 1; connectivity.push_back(segment_connectivity); // Copy nodes Vector<Real> source(dim), target(dim); for (UInt j = 0; j < dim; j++) { source(j) = it->first.source()[j]; target(j) = it->first.target()[j]; } nodes.push_back(source); nodes.push_back(target); // Copy associated element info if (valid_elemental_data) { associated_element->push_back(Element{type, it->second, _not_ghost}); associated_physical_name->push_back(current_physical_name); } } } AKANTU_DEBUG_OUT(); } template <UInt dim, ElementType type> void MeshSegmentIntersector<dim, type>::computeMeshQueryIntersectionPoint( const K::Segment_3 & /*query*/, UInt /*nb_old_nodes*/) { AKANTU_ERROR("The method: computeMeshQueryIntersectionPoint has not " "been implemented in class MeshSegmentIntersector!"); } template <UInt dim, ElementType type> void MeshSegmentIntersector<dim, type>::buildResultFromQueryList( const std::list<K::Segment_3> & query_list) { AKANTU_DEBUG_IN(); this->computeIntersectionQueryList(query_list); AKANTU_DEBUG_OUT(); } template <UInt dim, ElementType type> void MeshSegmentIntersector<dim, type>::computeSegments( const std::list<result_type> & intersections, std::set<pair_type, segmentPairsLess> & segments, const K::Segment_3 & query) { AKANTU_DEBUG_IN(); /* * Number of intersections = 0 means * * - query is completely outside mesh * - query is completely inside primitive * * We try to determine the case and still construct the segment list */ if (intersections.size() == 0) { // We look at all the primitives intersected by two rays // If there is one primitive in common, then query is inside // that primitive K::Ray_3 ray1(query.source(), query.target()); K::Ray_3 ray2(query.target(), query.source()); std::set<UInt> ray1_results, ray2_results; this->factory.getTree().all_intersected_primitives( ray1, std::inserter(ray1_results, ray1_results.begin())); this->factory.getTree().all_intersected_primitives( ray2, std::inserter(ray2_results, ray2_results.begin())); bool inside_primitive = false; UInt primitive_id = 0; std::set<UInt>::iterator ray2_it = ray2_results.begin(), ray2_end = ray2_results.end(); // Test if first list contains an element of second list for (; ray2_it != ray2_end && !inside_primitive; ++ray2_it) { if (ray1_results.find(*ray2_it) != ray1_results.end()) { inside_primitive = true; primitive_id = *ray2_it; } } if (inside_primitive) { segments.insert(std::make_pair(query, primitive_id)); } } else { typename std::list<result_type>::const_iterator it = intersections.begin(), end = intersections.end(); for (; it != end; ++it) { UInt el = (*it)->second; // Result of intersection is a segment if (const K::Segment_3 * segment = boost::get<K::Segment_3>(&((*it)->first))) { // Check if the segment was alread created segments.insert(std::make_pair(*segment, el)); } // Result of intersection is a point else if (const K::Point_3 * point = boost::get<K::Point_3>(&((*it)->first))) { // We only want to treat points differently if we're in 3D with Tetra4 // elements This should be optimized by compilator if (dim == 3 && type == _tetrahedron_4) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); TreeTypeHelper<Triangle<K>, K>::container_type facets; const Array<Real> & nodes = this->mesh.getNodes(); Array<UInt>::const_vector_iterator connectivity_vec = this->mesh.getConnectivity(type).begin(nb_nodes_per_element); const Vector<UInt> & el_connectivity = connectivity_vec[el]; Matrix<Real> node_coordinates(dim, nb_nodes_per_element); for (UInt i = 0; i < nb_nodes_per_element; i++) for (UInt j = 0; j < dim; j++) node_coordinates(j, i) = nodes(el_connectivity(i), j); this->factory.addPrimitive(node_coordinates, el, facets); // Local tree TreeTypeHelper<Triangle<K>, K>::tree * local_tree = new TreeTypeHelper<Triangle<K>, K>::tree(facets.begin(), facets.end()); // Compute local intersections (with current element) std::list<result_type> local_intersections; local_tree->all_intersections( query, std::back_inserter(local_intersections)); bool out_point_found = false; typename std::list<result_type>::const_iterator local_it = local_intersections.begin(), local_end = local_intersections.end(); for (; local_it != local_end; ++local_it) { if (const K::Point_3 * local_point = boost::get<K::Point_3>(&((*local_it)->first))) { if (!comparePoints(*point, *local_point)) { K::Segment_3 seg(*point, *local_point); segments.insert(std::make_pair(seg, el)); out_point_found = true; } } } if (!out_point_found) { TreeTypeHelper<Triangle<K>, K>::point_type a( node_coordinates(0, 0), node_coordinates(1, 0), node_coordinates(2, 0)), b(node_coordinates(0, 1), node_coordinates(1, 1), node_coordinates(2, 1)), c(node_coordinates(0, 2), node_coordinates(1, 2), node_coordinates(2, 2)), d(node_coordinates(0, 3), node_coordinates(1, 3), node_coordinates(2, 3)); K::Tetrahedron_3 tetra(a, b, c, d); const K::Point_3 * inside_point = NULL; if (tetra.has_on_bounded_side(query.source()) && !tetra.has_on_boundary(query.source())) inside_point = &query.source(); else if (tetra.has_on_bounded_side(query.target()) && !tetra.has_on_boundary(query.target())) inside_point = &query.target(); if (inside_point) { K::Segment_3 seg(*inside_point, *point); segments.insert(std::make_pair(seg, el)); } } delete local_tree; } } } } AKANTU_DEBUG_OUT(); } } // namespace akantu #endif // __AKANTU_MESH_SEGMENT_INTERSECTOR_TMPL_HH__ diff --git a/src/geometry/mesh_sphere_intersector.hh b/src/geometry/mesh_sphere_intersector.hh index 46c5e9f69..4066d67c4 100644 --- a/src/geometry/mesh_sphere_intersector.hh +++ b/src/geometry/mesh_sphere_intersector.hh @@ -1,119 +1,119 @@ /** * @file mesh_sphere_intersector.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jun 23 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Computation of mesh intersection with sphere(s) * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_SPHERE_INTERSECTOR_HH__ #define __AKANTU_MESH_SPHERE_INTERSECTOR_HH__ #include "aka_common.hh" #include "mesh_geom_intersector.hh" #include "mesh_geom_common.hh" /* -------------------------------------------------------------------------- */ namespace akantu { template <UInt dim, ElementType type> class MeshSphereIntersector : public MeshGeomIntersector<dim, type, Line_arc<cgal::Spherical>, cgal::Spherical::Sphere_3, cgal::Spherical> { using SK = cgal::Spherical; using K = cgal::Cartesian; /// Parent class type typedef MeshGeomIntersector<dim, type, Line_arc<SK>, SK::Sphere_3, SK> parent_type; /// Result of intersection function type typedef typename IntersectionTypeHelper<TreeTypeHelper<Triangle<K>, K>, K::Segment_3>::intersection_type result_type; /// Pair of intersection points and element id typedef std::pair<SK::Circular_arc_point_3, UInt> pair_type; public: /// Construct from mesh explicit MeshSphereIntersector(Mesh & mesh); /// Destructor virtual ~MeshSphereIntersector(); public: /// Construct the primitive tree object virtual void constructData(GhostType ghost_type = _not_ghost); /** * @brief Computes the intersection of the mesh with a sphere * * @param query (sphere) to compute the intersections with the mesh */ virtual void computeIntersectionQuery(const SK::Sphere_3 & /*query*/) { AKANTU_ERROR("This function is not implemented for spheres (It was " "to generic and has been replaced by " "computeMeshQueryIntersectionPoint"); } /// Compute intersection points between the mesh primitives (segments) and a /// query (surface in 3D or a curve in 2D), double intersection points for the /// same primitives are not considered. A maximum is set to the number of /// intersection nodes per element: 2 in 2D and 4 in 3D virtual void computeMeshQueryIntersectionPoint(const SK::Sphere_3 & query, UInt nb_old_nodes); /// Build the IGFEM mesh virtual void buildResultFromQueryList(const std::list<SK::Sphere_3> & /*query*/) { AKANTU_ERROR("This function is no longer implemented to split " "geometrical operations and dedicated result " "construction"); } /// Set the tolerance void setToleranceIntersectionOnNode(UInt tol) { this->tol_intersection_on_node = tol; } protected: /// tolerance for which the intersection is considered on the mesh node /// (relative to the segment lenght) Real tol_intersection_on_node; }; } // akantu #include "mesh_sphere_intersector_tmpl.hh" #endif // __AKANTU_MESH_SPHERE_INTERSECTOR_HH__ diff --git a/src/geometry/mesh_sphere_intersector_tmpl.hh b/src/geometry/mesh_sphere_intersector_tmpl.hh index 818132a63..d47d652ef 100644 --- a/src/geometry/mesh_sphere_intersector_tmpl.hh +++ b/src/geometry/mesh_sphere_intersector_tmpl.hh @@ -1,215 +1,215 @@ /** * @file mesh_sphere_intersector_tmpl.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jun 23 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Computation of mesh intersection with spheres * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_SPHERE_INTERSECTOR_TMPL_HH__ #define __AKANTU_MESH_SPHERE_INTERSECTOR_TMPL_HH__ #include "aka_common.hh" #include "mesh_geom_common.hh" #include "mesh_sphere_intersector.hh" #include "tree_type_helper.hh" namespace akantu { template <UInt dim, ElementType type> MeshSphereIntersector<dim, type>::MeshSphereIntersector(Mesh & mesh) : parent_type(mesh), tol_intersection_on_node(1e-10) { #if defined(AKANTU_IGFEM) if ((type == _triangle_3) || (type == _igfem_triangle_4) || (type == _igfem_triangle_5)) { const_cast<UInt &>(this->nb_seg_by_el) = 3; } else { AKANTU_ERROR("Not ready for mesh type " << type); } #else if ((type != _triangle_3)) AKANTU_ERROR("Not ready for mesh type " << type); #endif // initialize the intersection pointsss array with the spatial dimension this->intersection_points = new Array<Real>(0, dim); // A maximum is set to the number of intersection nodes per element to limit // the size of new_node_per_elem: 2 in 2D and 4 in 3D this->new_node_per_elem = new Array<UInt>(0, 1 + 4 * (dim - 1)); } template <UInt dim, ElementType type> MeshSphereIntersector<dim, type>::~MeshSphereIntersector() { delete this->new_node_per_elem; delete this->intersection_points; } template <UInt dim, ElementType type> void MeshSphereIntersector<dim, type>::constructData(GhostType ghost_type) { this->new_node_per_elem->resize(this->mesh.getNbElement(type, ghost_type)); this->new_node_per_elem->clear(); MeshGeomIntersector<dim, type, Line_arc<SK>, SK::Sphere_3, SK>::constructData( ghost_type); } template <UInt dim, ElementType type> void MeshSphereIntersector<dim, type>::computeMeshQueryIntersectionPoint( const SK::Sphere_3 & query, UInt nb_old_nodes) { /// function to replace computeIntersectionQuery in a more generic geometry /// module version // The newNodeEvent is not send from this method who only compute the // intersection points AKANTU_DEBUG_IN(); Array<Real> & nodes = this->mesh.getNodes(); UInt nb_node = nodes.size() + this->intersection_points->size(); // Tolerance for proximity checks should be defined by user Real global_tolerance = Math::getTolerance(); Math::setTolerance(tol_intersection_on_node); typedef boost::variant<pair_type> sk_inter_res; TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::const_iterator it = this->factory.getPrimitiveList().begin(), end = this->factory.getPrimitiveList().end(); for (; it != end; ++it) { // loop on the primitives (segments) std::list<sk_inter_res> s_results; CGAL::intersection(*it, query, std::back_inserter(s_results)); if (s_results.size() == 1) { // just one point if (pair_type * pair = boost::get<pair_type>(&s_results.front())) { if (pair->second == 1) { // not a point tangent to the sphere // the intersection point written as a vector Vector<Real> new_node(dim, 0.0); cgal::Cartesian::Point_3 point(CGAL::to_double(pair->first.x()), CGAL::to_double(pair->first.y()), CGAL::to_double(pair->first.z())); for (UInt i = 0; i < dim; i++) { new_node(i) = point[i]; } /// boolean to decide wheter intersection point is on a standard node /// of the mesh or not bool is_on_mesh = false; /// boolean to decide if this intersection point has been already /// computed for a neighbor element bool is_new = true; /// check if intersection point has already been computed UInt n = nb_old_nodes; // check if we already compute this intersection and add it as a node // for a neighboor element of another type auto existing_node = nodes.begin(dim); for (; n < nodes.size(); ++n) { // loop on the nodes from nb_old_nodes if (Math::are_vector_equal(dim, new_node.storage(), existing_node[n].storage())) { is_new = false; break; } } if (is_new) { auto intersection_points_it = this->intersection_points->begin(dim); auto intersection_points_end = this->intersection_points->end(dim); for (; intersection_points_it != intersection_points_end; ++intersection_points_it, ++n) { if (Math::are_vector_equal(dim, new_node.storage(), intersection_points_it->storage())) { is_new = false; break; } } } // get the initial and final points of the primitive (segment) and // write them as vectors cgal::Cartesian::Point_3 source_cgal( CGAL::to_double(it->source().x()), CGAL::to_double(it->source().y()), CGAL::to_double(it->source().z())); cgal::Cartesian::Point_3 target_cgal( CGAL::to_double(it->target().x()), CGAL::to_double(it->target().y()), CGAL::to_double(it->target().z())); Vector<Real> source(dim), target(dim); for (UInt i = 0; i < dim; i++) { source(i) = source_cgal[i]; target(i) = target_cgal[i]; } // Check if we are close from a node of the primitive (segment) if (Math::are_vector_equal(dim, source.storage(), new_node.storage()) || Math::are_vector_equal(dim, target.storage(), new_node.storage())) { is_on_mesh = true; is_new = false; } if (is_new) { // if the intersection point is a new one add it to the // list this->intersection_points->push_back(new_node); nb_node++; } // deduce the element id UInt element_id = it->id(); // fill the new_node_per_elem array if (!is_on_mesh) { // if the node is not on a mesh node UInt & nb_new_nodes_per_el = (*this->new_node_per_elem)(element_id, 0); nb_new_nodes_per_el += 1; AKANTU_DEBUG_ASSERT( 2 * nb_new_nodes_per_el < this->new_node_per_elem->getNbComponent(), "You might have to interface crossing the same material"); (*this->new_node_per_elem)(element_id, (2 * nb_new_nodes_per_el) - 1) = n; (*this->new_node_per_elem)(element_id, 2 * nb_new_nodes_per_el) = it->segId(); } } } } } Math::setTolerance(global_tolerance); AKANTU_DEBUG_OUT(); } } // akantu #endif // __AKANTU_MESH_SPHERE_INTERSECTOR_TMPL_HH__ diff --git a/src/geometry/tree_type_helper.hh b/src/geometry/tree_type_helper.hh index d43bdf549..f0cf08c21 100644 --- a/src/geometry/tree_type_helper.hh +++ b/src/geometry/tree_type_helper.hh @@ -1,109 +1,109 @@ /** * @file tree_type_helper.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Thu Feb 01 2018 * * @brief Converts element types of a mesh to CGAL primitive types * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TREE_TYPE_HELPER_HH__ #define __AKANTU_TREE_TYPE_HELPER_HH__ #include "aka_common.hh" #include "line_arc.hh" #include "tetrahedron.hh" #include "triangle.hh" #include "aabb_primitive.hh" #include "mesh_geom_common.hh" #include <CGAL/AABB_traits.h> #include <CGAL/AABB_tree.h> namespace akantu { /* -------------------------------------------------------------------------- */ /// Replacement class for algorithm that can't use the AABB tree types template <typename iterator> struct VoidTree { VoidTree(const iterator & /*begin*/, const iterator & /*end*/) {} }; /// Helper class used to ease the use of CGAL AABB tree algorithm template <class Primitive, class Kernel> struct TreeTypeHelper { static const bool is_valid = false; typedef Primitive primitive_type; typedef typename std::list<primitive_type> container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename CGAL::Point_3<Kernel> point_type; typedef VoidTree<iterator> tree; }; /// Helper class used to ease the use of intersections template <class TTHelper, class Query> struct IntersectionTypeHelper; /** * Macro used to specialize TreeTypeHelper * @param my_primitive associated primitive type * @param my_query query_type * @param my_kernel kernel type */ #define TREE_TYPE_HELPER_MACRO(my_primitive, my_query, my_kernel) \ template <> struct TreeTypeHelper<my_primitive<my_kernel>, my_kernel> { \ static const bool is_valid = true; \ typedef my_primitive<my_kernel> primitive_type; \ typedef my_primitive##_primitive aabb_primitive_type; \ typedef CGAL::Point_3<my_kernel> point_type; \ \ typedef std::list<primitive_type> container_type; \ typedef container_type::iterator iterator; \ typedef CGAL::AABB_traits<my_kernel, aabb_primitive_type> \ aabb_traits_type; \ typedef CGAL::AABB_tree<aabb_traits_type> tree; \ typedef tree::Primitive_id id_type; \ }; \ \ template <> \ struct IntersectionTypeHelper< \ TreeTypeHelper<my_primitive<my_kernel>, my_kernel>, my_query> { \ typedef boost::optional<TreeTypeHelper< \ my_primitive<my_kernel>, \ my_kernel>::tree::Intersection_and_primitive_id<my_query>::Type> \ intersection_type; \ } TREE_TYPE_HELPER_MACRO(Triangle, cgal::Cartesian::Segment_3, cgal::Cartesian); // TREE_TYPE_HELPER_MACRO(Line_arc, cgal::Spherical::Sphere_3, cgal::Spherical); #undef TREE_TYPE_HELPER_MACRO } // akantu #endif // __AKANTU_TREE_TYPE_HELPER_HH__ diff --git a/src/io/dumper/dumpable.cc b/src/io/dumper/dumpable.cc index 04997c49c..e35791864 100644 --- a/src/io/dumper/dumpable.cc +++ b/src/io/dumper/dumpable.cc @@ -1,285 +1,285 @@ /** * @file dumpable.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of the dumpable interface * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumpable.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include <io_helper.hh> namespace akantu { /* -------------------------------------------------------------------------- */ Dumpable::Dumpable() : default_dumper("") {} /* -------------------------------------------------------------------------- */ Dumpable::~Dumpable() { auto it = dumpers.begin(); auto end = dumpers.end(); for (; it != end; ++it) { delete it->second; } } /* -------------------------------------------------------------------------- */ void Dumpable::registerExternalDumper(DumperIOHelper & dumper, const std::string & dumper_name, const bool is_default) { this->dumpers[dumper_name] = &dumper; if (is_default) this->default_dumper = dumper_name; } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpMesh(const Mesh & mesh, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { this->addDumpMeshToDumper(this->default_dumper, mesh, spatial_dimension, ghost_type, element_kind); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpMeshToDumper(const std::string & dumper_name, const Mesh & mesh, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.registerMesh(mesh, spatial_dimension, ghost_type, element_kind); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFilteredMesh( const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { this->addDumpFilteredMeshToDumper(this->default_dumper, mesh, elements_filter, nodes_filter, spatial_dimension, ghost_type, element_kind); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFilteredMeshToDumper( const std::string & dumper_name, const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.registerFilteredMesh(mesh, elements_filter, nodes_filter, spatial_dimension, ghost_type, element_kind); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpField(const std::string & field_id) { this->addDumpFieldToDumper(this->default_dumper, field_id); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFieldToDumper(__attribute__((unused)) const std::string & dumper_name, __attribute__((unused)) const std::string & field_id) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFieldExternal(const std::string & field_id, dumper::Field * field) { this->addDumpFieldExternalToDumper(this->default_dumper, field_id, field); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFieldExternalToDumper(const std::string & dumper_name, const std::string & field_id, dumper::Field * field) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.registerField(field_id, field); } /* -------------------------------------------------------------------------- */ void Dumpable::removeDumpField(const std::string & field_id) { this->removeDumpFieldFromDumper(this->default_dumper, field_id); } /* -------------------------------------------------------------------------- */ void Dumpable::removeDumpFieldFromDumper(const std::string & dumper_name, const std::string & field_id) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.unRegisterField(field_id); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFieldVector(const std::string & field_id) { this->addDumpFieldVectorToDumper(this->default_dumper, field_id); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFieldVectorToDumper(__attribute__((unused)) const std::string & dumper_name, __attribute__((unused)) const std::string & field_id) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFieldTensor(const std::string & field_id) { this->addDumpFieldTensorToDumper(this->default_dumper, field_id); } /* -------------------------------------------------------------------------- */ void Dumpable::addDumpFieldTensorToDumper(__attribute__((unused)) const std::string & dumper_name, __attribute__((unused)) const std::string & field_id) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ void Dumpable::setDirectory(const std::string & directory) { this->setDirectoryToDumper(this->default_dumper, directory); } /* -------------------------------------------------------------------------- */ void Dumpable::setDirectoryToDumper(const std::string & dumper_name, const std::string & directory) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Dumpable::setBaseName(const std::string & basename) { this->setBaseNameToDumper(this->default_dumper, basename); } /* -------------------------------------------------------------------------- */ void Dumpable::setBaseNameToDumper(const std::string & dumper_name, const std::string & basename) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.setBaseName(basename); } /* -------------------------------------------------------------------------- */ void Dumpable::setTimeStepToDumper(Real time_step) { this->setTimeStepToDumper(this->default_dumper, time_step); } /* -------------------------------------------------------------------------- */ void Dumpable::setTimeStepToDumper(const std::string & dumper_name, Real time_step) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ void Dumpable::setTextModeToDumper(const std::string & dumper_name) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.getDumper().setMode(iohelper::TEXT); } /* -------------------------------------------------------------------------- */ void Dumpable::setTextModeToDumper() { DumperIOHelper & dumper = this->getDumper(this->default_dumper); dumper.getDumper().setMode(iohelper::TEXT); } /* -------------------------------------------------------------------------- */ void Dumpable::dump(const std::string & dumper_name) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.dump(); } /* -------------------------------------------------------------------------- */ void Dumpable::dump() { this->dump(this->default_dumper); } /* -------------------------------------------------------------------------- */ void Dumpable::dump(const std::string & dumper_name, UInt step) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.dump(step); } /* -------------------------------------------------------------------------- */ void Dumpable::dump(UInt step) { this->dump(this->default_dumper, step); } /* -------------------------------------------------------------------------- */ void Dumpable::dump(const std::string & dumper_name, Real time, UInt step) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.dump(time, step); } /* -------------------------------------------------------------------------- */ void Dumpable::dump(Real time, UInt step) { this->dump(this->default_dumper, time, step); } /* -------------------------------------------------------------------------- */ void Dumpable::internalAddDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id, dumper::Field * field) { DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.registerField(field_id, field); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Dumpable::getDumper() { return this->getDumper(this->default_dumper); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Dumpable::getDumper(const std::string & dumper_name) { auto it = this->dumpers.find(dumper_name); auto end = this->dumpers.end(); if (it == end) AKANTU_EXCEPTION("Dumper " << dumper_name << "has not been registered, yet."); return *(it->second); } /* -------------------------------------------------------------------------- */ std::string Dumpable::getDefaultDumperName() const { return this->default_dumper; } } // akantu #endif diff --git a/src/io/dumper/dumpable.hh b/src/io/dumper/dumpable.hh index 985e3b9f7..3ef6f269e 100644 --- a/src/io/dumper/dumpable.hh +++ b/src/io/dumper/dumpable.hh @@ -1,48 +1,47 @@ /** * @file dumpable.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Oct 26 2012 - * @date last modification: Tue Jan 06 2015 + * @date last modification: Wed Feb 03 2016 * * @brief Interface for object who wants to dump themselves * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_type_map.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DUMPABLE_HH__ #define __AKANTU_DUMPABLE_HH__ #ifdef AKANTU_USE_IOHELPER #include "dumpable_iohelper.hh" #else #include "dumpable_dummy.hh" #endif // AKANTU_USE_IOHELPER #endif /* __AKANTU_DUMPABLE_HH__ */ diff --git a/src/io/dumper/dumpable_dummy.hh b/src/io/dumper/dumpable_dummy.hh index 0b9fb4694..eb9420dfd 100644 --- a/src/io/dumper/dumpable_dummy.hh +++ b/src/io/dumper/dumpable_dummy.hh @@ -1,265 +1,264 @@ /** * @file dumpable_dummy.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Oct 26 2012 - * @date last modification: Fri Aug 21 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Interface for object who wants to dump themselves * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DUMPABLE_DUMMY_HH__ #define __AKANTU_DUMPABLE_DUMMY_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused" namespace dumper { class Field; } class DumperIOHelper; class Mesh; /* -------------------------------------------------------------------------- */ class Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Dumpable(){}; virtual ~Dumpable(){}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template <class T> inline void registerDumper(const std::string & dumper_name, const std::string & file_name = "", const bool is_default = false) {} void registerExternalDumper(DumperIOHelper * dumper, const std::string & dumper_name, const bool is_default = false) {} void addDumpMesh(const Mesh & mesh, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) {} void addDumpMeshToDumper(const std::string & dumper_name, const Mesh & mesh, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) { } void addDumpFilteredMesh(const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) { } void addDumpFilteredMeshToDumper( const std::string & dumper_name, const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) {} virtual void addDumpField(const std::string & field_id) { AKANTU_TO_IMPLEMENT(); } virtual void addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { AKANTU_TO_IMPLEMENT(); } virtual void addDumpFieldExternal(const std::string & field_id, dumper::Field * field) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } virtual void addDumpFieldExternalToDumper(const std::string & dumper_name, const std::string & field_id, dumper::Field * field) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } template <typename T> void addDumpFieldExternal(const std::string & field_id, const Array<T> & field) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } template <typename T> void addDumpFieldExternalToDumper(const std::string & dumper_name, const std::string & field_id, const Array<T> & field) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } template <typename T> void addDumpFieldExternal(const std::string & field_id, const ElementTypeMapArray<T> & field, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } template <typename T> void addDumpFieldExternalToDumper( const std::string & dumper_name, const std::string & field_id, const ElementTypeMapArray<T> & field, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void removeDumpField(const std::string & field_id) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void removeDumpFieldFromDumper(const std::string & dumper_name, const std::string & field_id) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void setDirecory(const std::string & directory) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void setDirectoryToDumper(const std::string & dumper_name, const std::string & directory) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void setBaseName(const std::string & basename) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void setBaseNameToDumper(const std::string & dumper_name, const std::string & basename) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void setTextModeToDumper(const std::string & dumper_name) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void setTextModeToDumper() { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void dump() { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void dump(const std::string & dumper_name) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void dump(UInt step) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void dump(const std::string & dumper_name, UInt step) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void dump(Real current_time, UInt step) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } void dump(const std::string & dumper_name, Real current_time, UInt step) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } protected: void internalAddDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id, dumper::Field * field) { AKANTU_DEBUG_WARNING("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } protected: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: DumperIOHelper & getDumper() { AKANTU_ERROR("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } DumperIOHelper & getDumper(const std::string & dumper_name) { AKANTU_ERROR("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } template <class T> T & getDumper(const std::string & dumper_name) { AKANTU_ERROR("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } std::string getDefaultDumperName() { AKANTU_ERROR("No dumper activated at compilation, turn on " "AKANTU_USE_IOHELPER in cmake."); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; #pragma GCC diagnostic pop } // akantu #endif /* __AKANTU_DUMPABLE_DUMMY_HH__ */ diff --git a/src/io/dumper/dumpable_inline_impl.hh b/src/io/dumper/dumpable_inline_impl.hh index 638462db5..012b570b4 100644 --- a/src/io/dumper/dumpable_inline_impl.hh +++ b/src/io/dumper/dumpable_inline_impl.hh @@ -1,134 +1,134 @@ /** * @file dumpable_inline_impl.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Wed Nov 08 2017 * * @brief Implementation of the Dumpable class * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPABLE_INLINE_IMPL_HH__ #define __AKANTU_DUMPABLE_INLINE_IMPL_HH__ /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumper_elemental_field.hh" #include "dumper_nodal_field.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <class T> inline void Dumpable::registerDumper(const std::string & dumper_name, const std::string & file_name, const bool is_default) { if (this->dumpers.find(dumper_name) != this->dumpers.end()) { AKANTU_DEBUG_INFO("Dumper " + dumper_name + "is already registered."); } std::string name = file_name; if (name == "") name = dumper_name; this->dumpers[dumper_name] = new T(name); if (is_default) this->default_dumper = dumper_name; } /* -------------------------------------------------------------------------- */ template <typename T> inline void Dumpable::addDumpFieldExternal(const std::string & field_id, const Array<T> & field) { this->addDumpFieldExternalToDumper<T>(this->default_dumper, field_id, field); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Dumpable::addDumpFieldExternalToDumper(const std::string & dumper_name, const std::string & field_id, const Array<T> & field) { dumper::Field * field_cont = new dumper::NodalField<T>(field); DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.registerField(field_id, field_cont); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Dumpable::addDumpFieldExternal(const std::string & field_id, const ElementTypeMapArray<T> & field, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { this->addDumpFieldExternalToDumper(this->default_dumper, field_id, field, spatial_dimension, ghost_type, element_kind); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Dumpable::addDumpFieldExternalToDumper( const std::string & dumper_name, const std::string & field_id, const ElementTypeMapArray<T> & field, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { dumper::Field * field_cont; #if defined(AKANTU_IGFEM) if (element_kind == _ek_igfem) { field_cont = new dumper::IGFEMElementalField<T>(field, spatial_dimension, ghost_type, element_kind); } else #endif field_cont = new dumper::ElementalField<T>(field, spatial_dimension, ghost_type, element_kind); DumperIOHelper & dumper = this->getDumper(dumper_name); dumper.registerField(field_id, field_cont); } /* -------------------------------------------------------------------------- */ template <class T> inline T & Dumpable::getDumper(const std::string & dumper_name) { DumperIOHelper & dumper = this->getDumper(dumper_name); try { auto & templated_dumper = dynamic_cast<T &>(dumper); return templated_dumper; } catch (std::bad_cast &) { AKANTU_EXCEPTION("Dumper " << dumper_name << " is not of type: " << debug::demangle(typeid(T).name())); } } /* -------------------------------------------------------------------------- */ } // akantu #endif #endif /* __AKANTU_DUMPABLE_INLINE_IMPL_HH__ */ diff --git a/src/io/dumper/dumpable_iohelper.hh b/src/io/dumper/dumpable_iohelper.hh index e9252526f..02bacd64f 100644 --- a/src/io/dumper/dumpable_iohelper.hh +++ b/src/io/dumper/dumpable_iohelper.hh @@ -1,192 +1,192 @@ /** * @file dumpable_iohelper.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jan 06 2015 - * @date last modification: Thu Nov 19 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Interface for object who wants to dump themselves * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_iohelper.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DUMPABLE_IOHELPER_HH__ #define __AKANTU_DUMPABLE_IOHELPER_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Dumpable(); virtual ~Dumpable(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// create a new dumper (of templated type T) and register it under /// dumper_name. file_name is used for construction of T. is default states if /// this dumper is the default dumper. template <class T> inline void registerDumper(const std::string & dumper_name, const std::string & file_name = "", const bool is_default = false); /// register an externally created dumper void registerExternalDumper(DumperIOHelper & dumper, const std::string & dumper_name, const bool is_default = false); /// register a mesh to the default dumper void addDumpMesh(const Mesh & mesh, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); /// register a mesh to the default identified by its name void addDumpMeshToDumper(const std::string & dumper_name, const Mesh & mesh, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); /// register a filtered mesh as the default dumper void addDumpFilteredMesh(const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); /// register a filtered mesh and provides a name void addDumpFilteredMeshToDumper( const std::string & dumper_name, const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); /// to implement virtual void addDumpField(const std::string & field_id); /// to implement virtual void addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id); /// add a field virtual void addDumpFieldExternal(const std::string & field_id, dumper::Field * field); virtual void addDumpFieldExternalToDumper(const std::string & dumper_name, const std::string & field_id, dumper::Field * field); template <typename T> inline void addDumpFieldExternal(const std::string & field_id, const Array<T> & field); template <typename T> inline void addDumpFieldExternalToDumper(const std::string & dumper_name, const std::string & field_id, const Array<T> & field); template <typename T> inline void addDumpFieldExternal(const std::string & field_id, const ElementTypeMapArray<T> & field, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); template <typename T> inline void addDumpFieldExternalToDumper( const std::string & dumper_name, const std::string & field_id, const ElementTypeMapArray<T> & field, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); void removeDumpField(const std::string & field_id); void removeDumpFieldFromDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldVector(const std::string & field_id); virtual void addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldTensor(const std::string & field_id); virtual void addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id); void setDirectory(const std::string & directory); void setDirectoryToDumper(const std::string & dumper_name, const std::string & directory); void setBaseName(const std::string & basename); void setBaseNameToDumper(const std::string & dumper_name, const std::string & basename); void setTimeStepToDumper(Real time_step); void setTimeStepToDumper(const std::string & dumper_name, Real time_step); void setTextModeToDumper(const std::string & dumper_name); void setTextModeToDumper(); virtual void dump(); virtual void dump(UInt step); virtual void dump(Real time, UInt step); virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); public: void internalAddDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id, dumper::Field * field); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: DumperIOHelper & getDumper(); DumperIOHelper & getDumper(const std::string & dumper_name); template <class T> T & getDumper(const std::string & dumper_name); std::string getDefaultDumperName() const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: using DumperMap = std::map<std::string, DumperIOHelper *>; using DumperSet = std::set<std::string>; DumperMap dumpers; std::string default_dumper; }; } // akantu #endif /* __AKANTU_DUMPABLE_IOHELPER_HH__ */ diff --git a/src/io/dumper/dumper_compute.hh b/src/io/dumper/dumper_compute.hh index 7af59b85c..0989f62b2 100644 --- a/src/io/dumper/dumper_compute.hh +++ b/src/io/dumper/dumper_compute.hh @@ -1,274 +1,274 @@ /** * @file dumper_compute.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Sun Dec 03 2017 * * @brief Field that map a function to another field * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_COMPUTE_HH__ #define __AKANTU_DUMPER_COMPUTE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dumper_field.hh" #include "dumper_iohelper.hh" #include "dumper_type_traits.hh" #include <io_helper.hh> /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ class ComputeFunctorInterface { public: virtual ~ComputeFunctorInterface() = default; virtual UInt getDim() = 0; virtual UInt getNbComponent(UInt old_nb_comp) = 0; }; /* -------------------------------------------------------------------------- */ template <typename return_type> class ComputeFunctorOutput : public ComputeFunctorInterface { public: ComputeFunctorOutput() = default; ~ComputeFunctorOutput() override = default; }; /* -------------------------------------------------------------------------- */ template <typename input_type, typename return_type> class ComputeFunctor : public ComputeFunctorOutput<return_type> { public: ComputeFunctor() = default; ~ComputeFunctor() override = default; virtual return_type func(const input_type & d, Element global_index) = 0; }; /* -------------------------------------------------------------------------- */ template <typename SubFieldCompute, typename _return_type> class FieldCompute : public Field { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using sub_iterator = typename SubFieldCompute::iterator; using sub_types = typename SubFieldCompute::types; using sub_return_type = typename sub_types::return_type; using return_type = _return_type; using data_type = typename sub_types::data_type; using types = TypeTraits<data_type, return_type, ElementTypeMapArray<data_type>>; class iterator { public: iterator(const sub_iterator & it, ComputeFunctor<sub_return_type, return_type> & func) : it(it), func(func) {} bool operator!=(const iterator & it) const { return it.it != this->it; } iterator operator++() { ++this->it; return *this; } UInt currentGlobalIndex() { return this->it.currentGlobalIndex(); } return_type operator*() { return func.func(*it, it.getCurrentElement()); } Element getCurrentElement() { return this->it.getCurrentElement(); } UInt element_type() { return this->it.element_type(); } protected: sub_iterator it; ComputeFunctor<sub_return_type, return_type> & func; }; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: FieldCompute(SubFieldCompute & cont, ComputeFunctorInterface & func) : sub_field(cont), func(dynamic_cast<ComputeFunctor<sub_return_type, return_type> &>( func)) { this->checkHomogeneity(); }; ~FieldCompute() override { delete &(this->sub_field); delete &(this->func); } void registerToDumper(const std::string & id, iohelper::Dumper & dumper) override { dumper.addElemDataField(id, *this); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: iterator begin() { return iterator(sub_field.begin(), func); } iterator end() { return iterator(sub_field.end(), func); } UInt getDim() { return func.getDim(); } UInt size() { throw; // return Functor::size(); return 0; } void checkHomogeneity() override { this->homogeneous = true; }; iohelper::DataType getDataType() { return iohelper::getDataType<data_type>(); } /// get the number of components of the hosted field ElementTypeMap<UInt> getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) override { ElementTypeMap<UInt> nb_components; const ElementTypeMap<UInt> & old_nb_components = this->sub_field.getNbComponents(dim, ghost_type, kind); ElementTypeMap<UInt>::type_iterator tit = old_nb_components.firstType(dim, ghost_type, kind); ElementTypeMap<UInt>::type_iterator end = old_nb_components.lastType(dim, ghost_type, kind); while (tit != end) { UInt nb_comp = old_nb_components(*tit, ghost_type); nb_components(*tit, ghost_type) = func.getNbComponent(nb_comp); ++tit; } return nb_components; }; /// for connection to a FieldCompute inline Field * connect(FieldComputeProxy & proxy) override; /// for connection to a FieldCompute ComputeFunctorInterface * connect(HomogenizerProxy & proxy) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: SubFieldCompute & sub_field; ComputeFunctor<sub_return_type, return_type> & func; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ class FieldComputeProxy { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: FieldComputeProxy(ComputeFunctorInterface & func) : func(func){}; inline static Field * createFieldCompute(Field * field, ComputeFunctorInterface & func) { /// that looks fishy an object passed as a ref and destroyed at their end of /// the function FieldComputeProxy compute_proxy(func); return field->connect(compute_proxy); } template <typename T> Field * connectToField(T * ptr) { if (dynamic_cast<ComputeFunctorOutput<Vector<Real>> *>(&func)) { return this->connectToFunctor<Vector<Real>>(ptr); } else if (dynamic_cast<ComputeFunctorOutput<Vector<UInt>> *>(&func)) { return this->connectToFunctor<Vector<UInt>>(ptr); } else if (dynamic_cast<ComputeFunctorOutput<Matrix<UInt>> *>(&func)) { return this->connectToFunctor<Matrix<UInt>>(ptr); } else if (dynamic_cast<ComputeFunctorOutput<Matrix<Real>> *>(&func)) { return this->connectToFunctor<Matrix<Real>>(ptr); } else throw; } template <typename output, typename T> Field * connectToFunctor(T * ptr) { auto * functor_ptr = new FieldCompute<T, output>(*ptr, func); return functor_ptr; } template <typename output, typename SubFieldCompute, typename return_type1, typename return_type2> Field * connectToFunctor(__attribute__((unused)) FieldCompute<FieldCompute<SubFieldCompute, return_type1>, return_type2> * ptr) { throw; // return new FieldCompute<T,output>(*ptr,func); return nullptr; } template <typename output, typename SubFieldCompute, typename return_type1, typename return_type2, typename return_type3, typename return_type4> Field * connectToFunctor( __attribute__((unused)) FieldCompute< FieldCompute<FieldCompute<FieldCompute<SubFieldCompute, return_type1>, return_type2>, return_type3>, return_type4> * ptr) { throw; // return new FieldCompute<T,output>(*ptr,func); return nullptr; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: ComputeFunctorInterface & func; }; /* -------------------------------------------------------------------------- */ /// for connection to a FieldCompute template <typename SubFieldCompute, typename return_type> inline Field * FieldCompute<SubFieldCompute, return_type>::connect(FieldComputeProxy & proxy) { return proxy.connectToField(this); } /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu #endif /* __AKANTU_DUMPER_COMPUTE_HH__ */ diff --git a/src/io/dumper/dumper_element_iterator.hh b/src/io/dumper/dumper_element_iterator.hh index 24319d083..9710b7d7c 100644 --- a/src/io/dumper/dumper_element_iterator.hh +++ b/src/io/dumper/dumper_element_iterator.hh @@ -1,178 +1,178 @@ /** * @file dumper_element_iterator.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Fri May 15 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Iterators for elemental fields * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_ELEMENT_ITERATOR_HH__ #define __AKANTU_DUMPER_ELEMENT_ITERATOR_HH__ /* -------------------------------------------------------------------------- */ #include "element.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <class types, template <class> class final_iterator> class element_iterator { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using it_type = typename types::it_type; using field_type = typename types::field_type; using array_type = typename types::array_type; using array_iterator = typename types::array_iterator; using iterator = final_iterator<types>; public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ element_iterator(const field_type & field, const typename field_type::type_iterator & t_it, const typename field_type::type_iterator & t_it_end, const array_iterator & array_it, const array_iterator & array_it_end, const GhostType ghost_type = _not_ghost) : field(field), tit(t_it), tit_end(t_it_end), array_it(array_it), array_it_end(array_it_end), ghost_type(ghost_type) {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: bool operator!=(const iterator & it) const { return (ghost_type != it.ghost_type) || (tit != it.tit || (array_it != it.array_it)); } iterator & operator++() { ++array_it; while (array_it == array_it_end && tit != tit_end) { ++tit; if (tit != tit_end) { const array_type & vect = field(*tit, ghost_type); UInt _nb_data_per_elem = getNbDataPerElem(*tit); UInt nb_component = vect.getNbComponent(); UInt size = (vect.size() * nb_component) / _nb_data_per_elem; array_it = vect.begin_reinterpret(_nb_data_per_elem, size); array_it_end = vect.end_reinterpret(_nb_data_per_elem, size); } } return *(static_cast<iterator *>(this)); }; ElementType getType() { return *tit; } UInt element_type() { return getIOHelperType(*tit); } Element getCurrentElement() { return Element{*tit, array_it.getCurrentIndex(), _not_ghost}; } UInt getNbDataPerElem(const ElementType & type) const { if (!nb_data_per_elem.exists(type, ghost_type)) return field(type, ghost_type).getNbComponent(); return nb_data_per_elem(type, ghost_type); } void setNbDataPerElem(const ElementTypeMap<UInt> & nb_data) { this->nb_data_per_elem = nb_data; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the field to iterate on const field_type & field; /// field iterator typename field_type::type_iterator tit; /// field iterator end typename field_type::type_iterator tit_end; /// array iterator array_iterator array_it; /// internal iterator end array_iterator array_it_end; /// ghost type identification const GhostType ghost_type; /// number of data per element ElementTypeMap<UInt> nb_data_per_elem; }; /* -------------------------------------------------------------------------- */ template <typename types> class elemental_field_iterator : public element_iterator<types, elemental_field_iterator> { public: /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ using parent = element_iterator<types, ::akantu::dumper::elemental_field_iterator>; using it_type = typename types::it_type; using return_type = typename types::return_type; using field_type = typename types::field_type; using array_iterator = typename types::array_iterator; public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ elemental_field_iterator(const field_type & field, const typename field_type::type_iterator & t_it, const typename field_type::type_iterator & t_it_end, const array_iterator & array_it, const array_iterator & array_it_end, const GhostType ghost_type = _not_ghost) : parent(field, t_it, t_it_end, array_it, array_it_end, ghost_type) {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ return_type operator*() { return *this->array_it; } private: }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu /* -------------------------------------------------------------------------- */ #endif /* __AKANTU_DUMPER_ELEMENT_ITERATOR_HH__ */ diff --git a/src/io/dumper/dumper_element_partition.hh b/src/io/dumper/dumper_element_partition.hh index 3718e35e2..4885ebe09 100644 --- a/src/io/dumper/dumper_element_partition.hh +++ b/src/io/dumper/dumper_element_partition.hh @@ -1,118 +1,118 @@ /** * @file dumper_element_partition.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Tue Jul 14 2015 + * @date last modification: Sun Dec 03 2017 * * @brief ElementPartition field * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ #ifdef AKANTU_IGFEM #include "dumper_igfem_element_partition.hh" #endif /* -------------------------------------------------------------------------- */ template <class types> class element_partition_field_iterator : public element_iterator<types, element_partition_field_iterator> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using parent = element_iterator<types, dumper::element_partition_field_iterator>; using return_type = typename SingleType<unsigned int, Vector, true>::return_type; using array_iterator = typename types::array_iterator; using field_type = typename types::field_type; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: element_partition_field_iterator( const field_type & field, const typename field_type::type_iterator & t_it, const typename field_type::type_iterator & t_it_end, const array_iterator & array_it, const array_iterator & array_it_end, const GhostType ghost_type = _not_ghost) : parent(field, t_it, t_it_end, array_it, array_it_end, ghost_type) { prank = Communicator::getStaticCommunicator().whoAmI(); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: return_type operator*() { return return_type(1, prank); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: UInt prank; }; /* -------------------------------------------------------------------------- */ template <bool filtered = false> class ElementPartitionField : public GenericElementalField<SingleType<UInt, Vector, filtered>, element_partition_field_iterator> { public: /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ using types = SingleType<UInt, Vector, filtered>; using iterator = element_partition_field_iterator<types>; using parent = GenericElementalField<types, element_partition_field_iterator>; using field_type = typename types::field_type; public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ ElementPartitionField(const field_type & field, UInt spatial_dimension = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) : parent(field, spatial_dimension, ghost_type, element_kind) { this->homogeneous = true; } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ UInt getDim() override { return 1; } }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu diff --git a/src/io/dumper/dumper_elemental_field.hh b/src/io/dumper/dumper_elemental_field.hh index c62bf7b6c..3caf94b40 100644 --- a/src/io/dumper/dumper_elemental_field.hh +++ b/src/io/dumper/dumper_elemental_field.hh @@ -1,77 +1,76 @@ /** * @file dumper_elemental_field.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Mon Aug 17 2015 + * @date last modification: Sun Dec 03 2017 * * @brief description of elemental fields * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_ELEMENTAL_FIELD_HH__ #define __AKANTU_DUMPER_ELEMENTAL_FIELD_HH__ /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "dumper_field.hh" #include "dumper_generic_elemental_field.hh" #ifdef AKANTU_IGFEM #include "dumper_igfem_elemental_field.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <typename T, template <class> class ret = Vector, bool filtered = false> class ElementalField : public GenericElementalField<SingleType<T, ret, filtered>, elemental_field_iterator> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using types = SingleType<T, ret, filtered>; using field_type = typename types::field_type; using iterator = elemental_field_iterator<types>; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ElementalField(const field_type & field, UInt spatial_dimension = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) : GenericElementalField<types, elemental_field_iterator>( field, spatial_dimension, ghost_type, element_kind) {} }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu #endif /* __AKANTU_DUMPER_ELEMENTAL_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_field.hh b/src/io/dumper/dumper_field.hh index 66544d73e..ebe765ce8 100644 --- a/src/io/dumper/dumper_field.hh +++ b/src/io/dumper/dumper_field.hh @@ -1,137 +1,137 @@ /** * @file dumper_field.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Common interface for fields * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_FIELD_HH__ #define __AKANTU_DUMPER_FIELD_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_iohelper.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ class FieldComputeProxy; class FieldComputeBaseInterface; class ComputeFunctorInterface; class HomogenizerProxy; /* -------------------------------------------------------------------------- */ /// Field interface class Field { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Field() = default; virtual ~Field() = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: #ifdef AKANTU_USE_IOHELPER /// register this to the provided dumper virtual void registerToDumper(const std::string & id, iohelper::Dumper & dumper) = 0; #endif /// set the number of data per item (used for elements fields at the moment) virtual void setNbData(__attribute__((unused)) UInt nb_data) { AKANTU_TO_IMPLEMENT(); }; /// set the number of data per elem (used for elements fields at the moment) virtual void setNbDataPerElem(__attribute__((unused)) const ElementTypeMap<UInt> & nb_data) { AKANTU_TO_IMPLEMENT(); }; /// set the number of data per elem (used for elements fields at the moment) virtual void setNbDataPerElem(__attribute__((unused)) UInt nb_data) { AKANTU_TO_IMPLEMENT(); }; /// get the number of components of the hosted field virtual ElementTypeMap<UInt> getNbComponents(__attribute__((unused)) UInt dim = _all_dimensions, __attribute__((unused)) GhostType ghost_type = _not_ghost, __attribute__((unused)) ElementKind kind = _ek_not_defined) { throw; }; /// for connection to a FieldCompute inline virtual Field * connect(__attribute__((unused)) FieldComputeProxy & proxy) { throw; }; /// for connection to a FieldCompute inline virtual ComputeFunctorInterface * connect(__attribute__((unused)) HomogenizerProxy & proxy) { throw; }; /// check if the same quantity of data for all element types virtual void checkHomogeneity() = 0; /// return the dumper name std::string getGroupName() { return group_name; }; /// return the id of the field std::string getID() { return field_id; }; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the flag to know if the field is homogeneous/contiguous virtual bool isHomogeneous() { return homogeneous; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the flag to know if it is homogeneous bool homogeneous{false}; /// the name of the group it was associated to std::string group_name; /// the name of the dumper it was associated to std::string field_id; }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu #endif /* __AKANTU_DUMPER_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_filtered_connectivity.hh b/src/io/dumper/dumper_filtered_connectivity.hh index 1dfe20e0d..bfda0e792 100644 --- a/src/io/dumper/dumper_filtered_connectivity.hh +++ b/src/io/dumper/dumper_filtered_connectivity.hh @@ -1,152 +1,152 @@ /** * @file dumper_filtered_connectivity.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Mon Aug 17 2015 + * @date last modification: Wed Nov 08 2017 * * @brief FilteredConnectivities field * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #include "dumper_generic_elemental_field.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <class types> class filtered_connectivity_field_iterator : public element_iterator<types, filtered_connectivity_field_iterator> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: typedef element_iterator<types, dumper::filtered_connectivity_field_iterator> parent; using return_type = typename types::return_type; using field_type = typename types::field_type; using array_iterator = typename types::array_iterator; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: filtered_connectivity_field_iterator( const field_type & field, const typename field_type::type_iterator & t_it, const typename field_type::type_iterator & t_it_end, const array_iterator & array_it, const array_iterator & array_it_end, const GhostType ghost_type = _not_ghost) : parent(field, t_it, t_it_end, array_it, array_it_end, ghost_type) {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: return_type operator*() { const Vector<UInt> & old_connect = *this->array_it; Vector<UInt> new_connect(old_connect.size()); Array<UInt>::const_iterator<UInt> nodes_begin = nodal_filter->begin(); Array<UInt>::const_iterator<UInt> nodes_end = nodal_filter->end(); for (UInt i(0); i < old_connect.size(); ++i) { Array<UInt>::const_iterator<UInt> new_id = std::find(nodes_begin, nodes_end, old_connect(i)); if (new_id == nodes_end) AKANTU_EXCEPTION("Node not found in the filter!"); new_connect(i) = new_id - nodes_begin; } return new_connect; } void setNodalFilter(const Array<UInt> & new_nodal_filter) { nodal_filter = &new_nodal_filter; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: const Array<UInt> * nodal_filter; }; /* -------------------------------------------------------------------------- */ class FilteredConnectivityField : public GenericElementalField<SingleType<UInt, Vector, true>, filtered_connectivity_field_iterator> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: typedef SingleType<UInt, Vector, true> types; using iterator = filtered_connectivity_field_iterator<types>; using field_type = types::field_type; typedef GenericElementalField<types, filtered_connectivity_field_iterator> parent; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: FilteredConnectivityField(const field_type & field, const Array<UInt> & nodal_filter, UInt spatial_dimension = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) : parent(field, spatial_dimension, ghost_type, element_kind), nodal_filter(nodal_filter) {} ~FilteredConnectivityField() override { // since the field is created in registerFilteredMesh it is destroyed here delete const_cast<field_type *>(&this->field); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: iterator begin() override { iterator it = parent::begin(); it.setNodalFilter(nodal_filter); return it; } iterator end() override { iterator it = parent::end(); it.setNodalFilter(nodal_filter); return it; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: const Array<UInt> & nodal_filter; }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu /* -------------------------------------------------------------------------- */ diff --git a/src/io/dumper/dumper_generic_elemental_field.hh b/src/io/dumper/dumper_generic_elemental_field.hh index bf532fb86..f616aa8b7 100644 --- a/src/io/dumper/dumper_generic_elemental_field.hh +++ b/src/io/dumper/dumper_generic_elemental_field.hh @@ -1,225 +1,225 @@ /** * @file dumper_generic_elemental_field.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Wed Nov 08 2017 * * @brief Generic interface for elemental fields * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_GENERIC_ELEMENTAL_FIELD_HH__ #define __AKANTU_DUMPER_GENERIC_ELEMENTAL_FIELD_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_element_iterator.hh" #include "dumper_field.hh" #include "dumper_homogenizing_field.hh" #include "element_type_map_filter.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <class _types, template <class> class iterator_type> class GenericElementalField : public Field { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: // check dumper_type_traits.hh for additional information over these types using types = _types; using data_type = typename types::data_type; using it_type = typename types::it_type; using field_type = typename types::field_type; using array_type = typename types::array_type; using array_iterator = typename types::array_iterator; using field_type_iterator = typename field_type::type_iterator; using iterator = iterator_type<types>; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: GenericElementalField(const field_type & field, UInt spatial_dimension = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) : field(field), spatial_dimension(spatial_dimension), ghost_type(ghost_type), element_kind(element_kind) { this->checkHomogeneity(); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get the number of components of the hosted field ElementTypeMap<UInt> getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) override { return this->field.getNbComponents(dim, ghost_type, kind); }; /// return the size of the contained data: i.e. the number of elements ? virtual UInt size() { checkHomogeneity(); return this->nb_total_element; } /// return the iohelper datatype to be dumped iohelper::DataType getDataType() { return iohelper::getDataType<data_type>(); } protected: /// return the number of entries per element UInt getNbDataPerElem(const ElementType & type, const GhostType & ghost_type = _not_ghost) const { if (!nb_data_per_elem.exists(type, ghost_type)) return field(type, ghost_type).getNbComponent(); return nb_data_per_elem(type, this->ghost_type); } /// check if the same quantity of data for all element types void checkHomogeneity() override; public: void registerToDumper(const std::string & id, iohelper::Dumper & dumper) override { dumper.addElemDataField(id, *this); }; /// for connection to a FieldCompute inline Field * connect(FieldComputeProxy & proxy) override { return proxy.connectToField(this); } /// for connection to a Homogenizer inline ComputeFunctorInterface * connect(HomogenizerProxy & proxy) override { return proxy.connectToField(this); }; virtual iterator begin() { field_type_iterator tit; field_type_iterator end; /// type iterators on the elemental field tit = this->field.firstType(this->spatial_dimension, this->ghost_type, this->element_kind); end = this->field.lastType(this->spatial_dimension, this->ghost_type, this->element_kind); /// skip all types without data ElementType type = *tit; for (; tit != end && this->field(*tit, this->ghost_type).size() == 0; ++tit) { } type = *tit; if (tit == end) return this->end(); /// getting information for the field of the given type const array_type & vect = this->field(type, this->ghost_type); UInt nb_data_per_elem = this->getNbDataPerElem(type); UInt nb_component = vect.getNbComponent(); UInt size = (vect.size() * nb_component) / nb_data_per_elem; /// define element-wise iterator array_iterator it = vect.begin_reinterpret(nb_data_per_elem, size); array_iterator it_end = vect.end_reinterpret(nb_data_per_elem, size); /// define data iterator iterator rit = iterator(this->field, tit, end, it, it_end, this->ghost_type); rit.setNbDataPerElem(this->nb_data_per_elem); return rit; } virtual iterator end() { field_type_iterator tit; field_type_iterator end; tit = this->field.firstType(this->spatial_dimension, this->ghost_type, this->element_kind); end = this->field.lastType(this->spatial_dimension, this->ghost_type, this->element_kind); ElementType type = *tit; for (; tit != end; ++tit) type = *tit; const array_type & vect = this->field(type, this->ghost_type); UInt nb_data = this->getNbDataPerElem(type); UInt nb_component = vect.getNbComponent(); UInt size = (vect.size() * nb_component) / nb_data; array_iterator it = vect.end_reinterpret(nb_data, size); iterator rit = iterator(this->field, end, end, it, it, this->ghost_type); rit.setNbDataPerElem(this->nb_data_per_elem); return rit; } virtual UInt getDim() { if (this->homogeneous) { field_type_iterator tit = this->field.firstType( this->spatial_dimension, this->ghost_type, this->element_kind); return this->getNbDataPerElem(*tit); } throw; return 0; } void setNbDataPerElem(const ElementTypeMap<UInt> & nb_data) override { nb_data_per_elem = nb_data; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the ElementTypeMapArray embedded in the field const field_type & field; /// total number of elements UInt nb_total_element; /// the spatial dimension of the problem UInt spatial_dimension; /// whether this is a ghost field or not (for type selection) GhostType ghost_type; /// The element kind to operate on ElementKind element_kind; /// The number of data per element type ElementTypeMap<UInt> nb_data_per_elem; }; /* -------------------------------------------------------------------------- */ #include "dumper_generic_elemental_field_tmpl.hh" /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu #endif /* __AKANTU_DUMPER_GENERIC_ELEMENTAL_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_generic_elemental_field_tmpl.hh b/src/io/dumper/dumper_generic_elemental_field_tmpl.hh index 80b6a524a..f22b9be0f 100644 --- a/src/io/dumper/dumper_generic_elemental_field_tmpl.hh +++ b/src/io/dumper/dumper_generic_elemental_field_tmpl.hh @@ -1,69 +1,69 @@ /** * @file dumper_generic_elemental_field_tmpl.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief Implementation of the template functions of the ElementalField * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ template <class types, template <class> class iterator> void GenericElementalField<types, iterator>::checkHomogeneity() { using field_type_iterator = typename field_type::type_iterator; using array_type = typename field_type::array_type; field_type_iterator tit; field_type_iterator end; tit = field.firstType(spatial_dimension, ghost_type, element_kind); end = field.lastType(spatial_dimension, ghost_type, element_kind); this->nb_total_element = 0; UInt nb_comp = 0; bool homogen = true; if (tit != end) { nb_comp = this->field(*tit, ghost_type).getNbComponent(); for (; tit != end; ++tit) { const array_type & vect = this->field(*tit, ghost_type); UInt nb_element = vect.size(); UInt nb_comp_cur = vect.getNbComponent(); if (homogen && nb_comp != nb_comp_cur) homogen = false; this->nb_total_element += nb_element; // this->nb_data_per_elem(*tit,this->ghost_type) = nb_comp_cur; } if (!homogen) nb_comp = 0; } this->homogeneous = homogen; } /* -------------------------------------------------------------------------- */ diff --git a/src/io/dumper/dumper_homogenizing_field.hh b/src/io/dumper/dumper_homogenizing_field.hh index ba39b1986..c95bf75bb 100644 --- a/src/io/dumper/dumper_homogenizing_field.hh +++ b/src/io/dumper/dumper_homogenizing_field.hh @@ -1,216 +1,216 @@ /** * @file dumper_homogenizing_field.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Tue Jul 14 2015 + * @date last modification: Wed Nov 08 2017 * * @brief description of field homogenizing field * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_HOMOGENIZING_FIELD_HH__ #define __AKANTU_DUMPER_HOMOGENIZING_FIELD_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_compute.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <typename type> inline type typeConverter(const type & input, __attribute__((unused)) Vector<typename type::value_type> & res, __attribute__((unused)) UInt nb_data) { throw; return input; } /* -------------------------------------------------------------------------- */ template <typename type> inline Matrix<type> typeConverter(const Matrix<type> & input, Vector<type> & res, UInt nb_data) { Matrix<type> tmp(res.storage(), input.rows(), nb_data / input.rows()); Matrix<type> tmp2(tmp, true); return tmp2; } /* -------------------------------------------------------------------------- */ template <typename type> inline Vector<type> typeConverter(__attribute__((unused)) const Vector<type> & input, __attribute__((unused)) Vector<type> & res, __attribute__((unused)) UInt nb_data) { return res; } /* -------------------------------------------------------------------------- */ template <typename type> class AvgHomogenizingFunctor : public ComputeFunctor<type, type> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ using value_type = typename type::value_type; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: AvgHomogenizingFunctor(ElementTypeMap<UInt> & nb_datas) { ElementTypeMap<UInt>::type_iterator tit = nb_datas.firstType(); ElementTypeMap<UInt>::type_iterator end = nb_datas.lastType(); nb_data = nb_datas(*tit); for (; tit != end; ++tit) if (nb_data != nb_datas(*tit)) throw; } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ type func(const type & d, Element /*global_index*/) override { Vector<value_type> res(this->nb_data); if (d.size() % this->nb_data) throw; UInt nb_to_average = d.size() / this->nb_data; value_type * ptr = d.storage(); for (UInt i = 0; i < nb_to_average; ++i) { Vector<value_type> tmp(ptr, this->nb_data); res += tmp; ptr += this->nb_data; } res /= nb_to_average; return typeConverter(d, res, this->nb_data); }; UInt getDim() override { return nb_data; }; UInt getNbComponent(UInt /*old_nb_comp*/) override { throw; }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ /// The size of data: i.e. the size of the vector to be returned UInt nb_data; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ class HomogenizerProxy { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: HomogenizerProxy() = default; public: inline static ComputeFunctorInterface * createHomogenizer(Field & field); template <typename T> inline ComputeFunctorInterface * connectToField(T * field) { ElementTypeMap<UInt> nb_components = field->getNbComponents(); using ret_type = typename T::types::return_type; return this->instantiateHomogenizer<ret_type>(nb_components); } template <typename ret_type> inline ComputeFunctorInterface * instantiateHomogenizer(ElementTypeMap<UInt> & nb_components); }; /* -------------------------------------------------------------------------- */ template <typename ret_type> inline ComputeFunctorInterface * HomogenizerProxy::instantiateHomogenizer(ElementTypeMap<UInt> & nb_components) { using Homogenizer = dumper::AvgHomogenizingFunctor<ret_type>; auto * foo = new Homogenizer(nb_components); return foo; } template <> inline ComputeFunctorInterface * HomogenizerProxy::instantiateHomogenizer<Vector<iohelper::ElemType>>( __attribute__((unused)) ElementTypeMap<UInt> & nb_components) { throw; return nullptr; } /* -------------------------------------------------------------------------- */ /// for connection to a FieldCompute template <typename SubFieldCompute, typename return_type> inline ComputeFunctorInterface * FieldCompute<SubFieldCompute, return_type>::connect(HomogenizerProxy & proxy) { return proxy.connectToField(this); } /* -------------------------------------------------------------------------- */ inline ComputeFunctorInterface * HomogenizerProxy::createHomogenizer(Field & field) { HomogenizerProxy homogenizer_proxy; return field.connect(homogenizer_proxy); } /* -------------------------------------------------------------------------- */ // inline ComputeFunctorInterface & createHomogenizer(Field & field){ // HomogenizerProxy::createHomogenizer(field); // throw; // ComputeFunctorInterface * ptr = NULL; // return *ptr; // } // /* -------------------------------------------------------------------------- // */ __END_AKANTU_DUMPER__ } // namespace akantu #endif /* __AKANTU_DUMPER_HOMOGENIZING_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_internal_material_field.hh b/src/io/dumper/dumper_internal_material_field.hh index 26924dda3..c9410ace0 100644 --- a/src/io/dumper/dumper_internal_material_field.hh +++ b/src/io/dumper/dumper_internal_material_field.hh @@ -1,73 +1,72 @@ /** * @file dumper_internal_material_field.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Sep 17 2015 + * @date last modification: Wed Nov 08 2017 * * @brief description of material internal field * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_INTERNAL_MATERIAL_FIELD_HH__ #define __AKANTU_DUMPER_INTERNAL_MATERIAL_FIELD_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_quadrature_point_iterator.hh" #ifdef AKANTU_IGFEM #include "dumper_igfem_material_internal_field.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <typename T, bool filtered = false> class InternalMaterialField : public GenericElementalField<SingleType<T, Vector, filtered>, quadrature_point_iterator> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using types = SingleType<T, Vector, filtered>; using parent = GenericElementalField<types, quadrature_point_iterator>; using field_type = typename types::field_type; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ InternalMaterialField(const field_type & field, UInt spatial_dimension = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) : parent(field, spatial_dimension, ghost_type, element_kind) {} }; __END_AKANTU_DUMPER__ } // akantu #endif /* __AKANTU_DUMPER_INTERNAL_MATERIAL_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_iohelper.cc b/src/io/dumper/dumper_iohelper.cc index ce23d1089..d4c9443c0 100644 --- a/src/io/dumper/dumper_iohelper.cc +++ b/src/io/dumper/dumper_iohelper.cc @@ -1,318 +1,317 @@ /** * @file dumper_iohelper.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Oct 26 2012 - * @date last modification: Thu Sep 17 2015 + * @date last modification: Tue Feb 20 2018 * * @brief implementation of DumperIOHelper * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <io_helper.hh> #include "dumper_elemental_field.hh" #include "dumper_filtered_connectivity.hh" #include "dumper_iohelper.hh" #include "dumper_nodal_field.hh" #include "dumper_variable.hh" #include "mesh.hh" #if defined(AKANTU_IGFEM) #include "dumper_igfem_connectivity.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ DumperIOHelper::DumperIOHelper() = default; /* -------------------------------------------------------------------------- */ DumperIOHelper::~DumperIOHelper() { for (auto it = fields.begin(); it != fields.end(); ++it) { delete it->second; } delete dumper; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setParallelContext(bool is_parallel) { UInt whoami = Communicator::getStaticCommunicator().whoAmI(); UInt nb_proc = Communicator::getStaticCommunicator().getNbProc(); if (is_parallel) dumper->setParallelContext(whoami, nb_proc); else dumper->setParallelContext(0, 1); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setDirectory(const std::string & directory) { this->directory = directory; dumper->setPrefix(directory); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setBaseName(const std::string & basename) { filename = basename; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setTimeStep(Real time_step) { if (!time_activated) this->dumper->activateTimeDescFiles(time_step); else this->dumper->setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump() { try { dumper->dump(filename, count); } catch (iohelper::IOHelperException & e) { AKANTU_ERROR( "I was not able to dump your data with a Dumper: " << e.what()); } ++count; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(UInt step) { this->count = step; this->dump(); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(Real current_time, UInt step) { this->dumper->setCurrentTime(current_time); this->dump(step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerMesh(const Mesh & mesh, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { #if defined(AKANTU_IGFEM) if (element_kind == _ek_igfem) { registerField("connectivities", new dumper::IGFEMConnectivityField( mesh.getConnectivities(), spatial_dimension, ghost_type)); } else #endif registerField("connectivities", new dumper::ElementalField<UInt>(mesh.getConnectivities(), spatial_dimension, ghost_type, element_kind)); registerField("positions", new dumper::NodalField<Real>(mesh.getNodes())); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerFilteredMesh( const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { auto * f_connectivities = new ElementTypeMapArrayFilter<UInt>( mesh.getConnectivities(), elements_filter); this->registerField("connectivities", new dumper::FilteredConnectivityField( *f_connectivities, nodes_filter, spatial_dimension, ghost_type, element_kind)); this->registerField("positions", new dumper::NodalField<Real, true>( mesh.getNodes(), 0, 0, &nodes_filter)); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerField(const std::string & field_id, dumper::Field * field) { auto it = fields.find(field_id); if (it != fields.end()) { AKANTU_DEBUG_WARNING( "The field " << field_id << " is already registered in this Dumper. Field ignored."); return; } fields[field_id] = field; field->registerToDumper(field_id, *dumper); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::unRegisterField(const std::string & field_id) { auto it = fields.find(field_id); if (it == fields.end()) { AKANTU_DEBUG_WARNING( "The field " << field_id << " is not registered in this Dumper. Nothing to do."); return; } delete it->second; fields.erase(it); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerVariable(const std::string & variable_id, dumper::VariableBase * variable) { auto it = variables.find(variable_id); if (it != variables.end()) { AKANTU_DEBUG_WARNING( "The Variable " << variable_id << " is already registered in this Dumper. Variable ignored."); return; } variables[variable_id] = variable; variable->registerToDumper(variable_id, *dumper); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::unRegisterVariable(const std::string & variable_id) { auto it = variables.find(variable_id); if (it == variables.end()) { AKANTU_DEBUG_WARNING( "The variable " << variable_id << " is not registered in this Dumper. Nothing to do."); return; } delete it->second; variables.erase(it); } /* -------------------------------------------------------------------------- */ template <ElementType type> iohelper::ElemType getIOHelperType() { AKANTU_TO_IMPLEMENT(); return iohelper::MAX_ELEM_TYPE; } template <> iohelper::ElemType getIOHelperType<_point_1>() { return iohelper::POINT_SET; } template <> iohelper::ElemType getIOHelperType<_segment_2>() { return iohelper::LINE1; } template <> iohelper::ElemType getIOHelperType<_segment_3>() { return iohelper::LINE2; } template <> iohelper::ElemType getIOHelperType<_triangle_3>() { return iohelper::TRIANGLE1; } template <> iohelper::ElemType getIOHelperType<_triangle_6>() { return iohelper::TRIANGLE2; } template <> iohelper::ElemType getIOHelperType<_quadrangle_4>() { return iohelper::QUAD1; } template <> iohelper::ElemType getIOHelperType<_quadrangle_8>() { return iohelper::QUAD2; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_4>() { return iohelper::TETRA1; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_10>() { return iohelper::TETRA2; } template <> iohelper::ElemType getIOHelperType<_hexahedron_8>() { return iohelper::HEX1; } template <> iohelper::ElemType getIOHelperType<_hexahedron_20>() { return iohelper::HEX2; } template <> iohelper::ElemType getIOHelperType<_pentahedron_6>() { return iohelper::PRISM1; } template <> iohelper::ElemType getIOHelperType<_pentahedron_15>() { return iohelper::PRISM2; } #if defined(AKANTU_COHESIVE_ELEMENT) template <> iohelper::ElemType getIOHelperType<_cohesive_1d_2>() { return iohelper::COH1D2; } template <> iohelper::ElemType getIOHelperType<_cohesive_2d_4>() { return iohelper::COH2D4; } template <> iohelper::ElemType getIOHelperType<_cohesive_2d_6>() { return iohelper::COH2D6; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_6>() { return iohelper::COH3D6; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_12>() { return iohelper::COH3D12; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_8>() { return iohelper::COH3D8; } // template <> // iohelper::ElemType getIOHelperType<_cohesive_3d_16>() { return // iohelper::COH3D16; } #endif #if defined(AKANTU_STRUCTURAL_MECHANICS) template <> iohelper::ElemType getIOHelperType<_bernoulli_beam_2>() { return iohelper::BEAM2; } template <> iohelper::ElemType getIOHelperType<_bernoulli_beam_3>() { return iohelper::BEAM3; } #endif /* -------------------------------------------------------------------------- */ UInt getIOHelperType(ElementType type) { UInt ioh_type = iohelper::MAX_ELEM_TYPE; #define GET_IOHELPER_TYPE(type) ioh_type = getIOHelperType<type>(); AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_IOHELPER_TYPE); #undef GET_IOHELPER_TYPE return ioh_type; } /* -------------------------------------------------------------------------- */ } // akantu namespace iohelper { template <> DataType getDataType<akantu::NodeType>() { return _int; } } diff --git a/src/io/dumper/dumper_iohelper.hh b/src/io/dumper/dumper_iohelper.hh index 862e79e98..f824215bd 100644 --- a/src/io/dumper/dumper_iohelper.hh +++ b/src/io/dumper/dumper_iohelper.hh @@ -1,159 +1,158 @@ /** * @file dumper_iohelper.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Oct 26 2012 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Sun Dec 03 2017 * * @brief Define the akantu dumper interface for IOhelper dumpers * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_types.hh" #include "element_type_map.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DUMPER_IOHELPER_HH__ #define __AKANTU_DUMPER_IOHELPER_HH__ /* -------------------------------------------------------------------------- */ namespace iohelper { class Dumper; } namespace akantu { UInt getIOHelperType(ElementType type); namespace dumper { class Field; class VariableBase; } class Mesh; class DumperIOHelper { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DumperIOHelper(); virtual ~DumperIOHelper(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// register a given Mesh for the current dumper virtual void registerMesh(const Mesh & mesh, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); /// register a filtered Mesh (provided filter lists) for the current dumper virtual void registerFilteredMesh(const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined); /// register a Field object identified by name and provided by pointer void registerField(const std::string & field_id, dumper::Field * field); /// remove the Field identified by name from managed fields void unRegisterField(const std::string & field_id); /// register a VariableBase object identified by name and provided by pointer void registerVariable(const std::string & variable_id, dumper::VariableBase * variable); /// remove a VariableBase identified by name from managed fields void unRegisterVariable(const std::string & variable_id); /// request dump: this calls IOHelper dump routine virtual void dump(); /// request dump: this first set the current step and then calls IOHelper dump /// routine virtual void dump(UInt step); /// request dump: this first set the current step and current time and then /// calls IOHelper dump routine virtual void dump(Real current_time, UInt step); /// set the parallel context for IOHeper virtual void setParallelContext(bool is_parallel); /// set the directory where to generate the dumped files virtual void setDirectory(const std::string & directory); /// set the base name (needed by most IOHelper dumpers) virtual void setBaseName(const std::string & basename); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// direct access to the iohelper::Dumper object AKANTU_GET_MACRO(Dumper, *dumper, iohelper::Dumper &) /// set the timestep of the iohelper::Dumper void setTimeStep(Real time_step); public: /* ------------------------------------------------------------------------ */ /* Variable wrapper */ template <typename T, bool is_scal = std::is_arithmetic<T>::value> class Variable; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// internal iohelper::Dumper iohelper::Dumper * dumper; using Fields = std::map<std::string, dumper::Field *>; using Variables = std::map<std::string, dumper::VariableBase *>; /// list of registered fields to dump Fields fields; Variables variables; /// dump counter UInt count{0}; /// directory name std::string directory; /// filename prefix std::string filename; /// is time tracking activated in the dumper bool time_activated{false}; }; } // akantu #endif /* __AKANTU_DUMPER_IOHELPER_HH__ */ diff --git a/src/io/dumper/dumper_iohelper_paraview.cc b/src/io/dumper/dumper_iohelper_paraview.cc index 4527586fa..fb8531321 100644 --- a/src/io/dumper/dumper_iohelper_paraview.cc +++ b/src/io/dumper/dumper_iohelper_paraview.cc @@ -1,67 +1,66 @@ /** - * @file dumper_paraview.cc + * @file dumper_iohelper_paraview.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sun Sep 26 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Jan 22 2018 * * @brief implementations of DumperParaview * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_iohelper_paraview.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <fstream> #include <io_helper.hh> /* -------------------------------------------------------------------------- */ namespace akantu { DumperParaview::DumperParaview(const std::string & filename, const std::string & directory, bool parallel) : DumperIOHelper() { iohelper::DumperParaview * dumper_para = new iohelper::DumperParaview(); dumper = dumper_para; setBaseName(filename); this->setParallelContext(parallel); dumper_para->setMode(iohelper::BASE64); dumper_para->setPrefix(directory); dumper_para->init(); } /* -------------------------------------------------------------------------- */ DumperParaview::~DumperParaview() = default; /* -------------------------------------------------------------------------- */ void DumperParaview::setBaseName(const std::string & basename) { DumperIOHelper::setBaseName(basename); static_cast<iohelper::DumperParaview *>(dumper)->setVTUSubDirectory(filename + "-VTU"); } } // namespace akantu diff --git a/src/io/dumper/dumper_iohelper_paraview.hh b/src/io/dumper/dumper_iohelper_paraview.hh index eac1bf120..312045070 100644 --- a/src/io/dumper/dumper_iohelper_paraview.hh +++ b/src/io/dumper/dumper_iohelper_paraview.hh @@ -1,72 +1,71 @@ /** - * @file dumper_paraview.hh + * @file dumper_iohelper_paraview.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Jan 22 2018 * * @brief Dumper Paraview using IOHelper * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DUMPER_PARAVIEW_HH__ #define __AKANTU_DUMPER_PARAVIEW_HH__ #include "dumper_iohelper.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class DumperParaview : public DumperIOHelper { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DumperParaview(const std::string & filename, const std::string & directory = "./paraview", bool parallel = true); ~DumperParaview() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: // void dump(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: void setBaseName(const std::string & basename) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; } // akantu #endif /* __AKANTU_DUMPER_PARAVIEW_HH__ */ diff --git a/src/io/dumper/dumper_material_padders.hh b/src/io/dumper/dumper_material_padders.hh index df66fb2cf..5c5501f53 100644 --- a/src/io/dumper/dumper_material_padders.hh +++ b/src/io/dumper/dumper_material_padders.hh @@ -1,289 +1,289 @@ /** * @file dumper_material_padders.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Fri Mar 27 2015 + * @date last modification: Wed Nov 29 2017 * * @brief Material padders for plane stress/ plane strain * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_MATERIAL_PADDERS_HH__ #define __AKANTU_DUMPER_MATERIAL_PADDERS_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_padding_helper.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ class MaterialFunctor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialFunctor(const SolidMechanicsModel & model) : model(model), material_index(model.getMaterialByElement()), nb_data_per_element("nb_data_per_element", model.getID(), model.getMemoryID()), spatial_dimension(model.getSpatialDimension()) {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ /// return the material from the global element index const Material & getMaterialFromGlobalIndex(Element global_index) { UInt index = global_index.element; UInt material_id = material_index(global_index.type)(index); const Material & material = model.getMaterial(material_id); return material; } /// return the type of the element from global index ElementType getElementTypeFromGlobalIndex(Element global_index) { return global_index.type; } protected: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ /// all material padders probably need access to solid mechanics model const SolidMechanicsModel & model; /// they also need an access to the map from global ids to material id and /// local ids const ElementTypeMapArray<UInt> & material_index; /// the number of data per element const ElementTypeMapArray<UInt> nb_data_per_element; UInt spatial_dimension; }; /* -------------------------------------------------------------------------- */ template <class T, class R> class MaterialPadder : public MaterialFunctor, public PadderGeneric<Vector<T>, R> { public: MaterialPadder(const SolidMechanicsModel & model) : MaterialFunctor(model) {} }; /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> class StressPadder : public MaterialPadder<Real, Matrix<Real>> { public: StressPadder(const SolidMechanicsModel & model) : MaterialPadder<Real, Matrix<Real>>(model) { this->setPadding(3, 3); } inline Matrix<Real> func(const Vector<Real> & in, Element global_element_id) override { UInt nrows = spatial_dimension; UInt ncols = in.size() / nrows; UInt nb_data = in.size() / (nrows * nrows); Matrix<Real> stress = this->pad(in, nrows, ncols, nb_data); const Material & material = this->getMaterialFromGlobalIndex(global_element_id); bool plane_strain = true; if (spatial_dimension == 2) plane_strain = !((bool)material.getParam("Plane_Stress")); if (plane_strain) { Real nu = material.getParam("nu"); for (UInt d = 0; d < nb_data; ++d) { stress(2, 2 + 3 * d) = nu * (stress(0, 0 + 3 * d) + stress(1, 1 + 3 * d)); } } return stress; } UInt getDim() override { return 9; }; UInt getNbComponent(UInt /*old_nb_comp*/) override { return this->getDim(); }; }; /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> class StrainPadder : public MaterialFunctor, public PadderGeneric<Matrix<Real>, Matrix<Real>> { public: StrainPadder(const SolidMechanicsModel & model) : MaterialFunctor(model) { this->setPadding(3, 3); } inline Matrix<Real> func(const Matrix<Real> & in, Element global_element_id) override { UInt nrows = spatial_dimension; UInt nb_data = in.size() / (nrows * nrows); Matrix<Real> strain = this->pad(in, nb_data); const Material & material = this->getMaterialFromGlobalIndex(global_element_id); bool plane_stress = material.getParam("Plane_Stress"); if (plane_stress) { Real nu = material.getParam("nu"); for (UInt d = 0; d < nb_data; ++d) { strain(2, 2 + 3 * d) = nu / (nu - 1) * (strain(0, 0 + 3 * d) + strain(1, 1 + 3 * d)); } } return strain; } UInt getDim() override { return 9; }; UInt getNbComponent(UInt /*old_nb_comp*/) override { return this->getDim(); }; }; /* -------------------------------------------------------------------------- */ template <bool green_strain> class ComputeStrain : public MaterialFunctor, public ComputeFunctor<Vector<Real>, Matrix<Real>> { public: ComputeStrain(const SolidMechanicsModel & model) : MaterialFunctor(model) {} inline Matrix<Real> func(const Vector<Real> & in, Element /*global_element_id*/) override { UInt nrows = spatial_dimension; UInt ncols = in.size() / nrows; UInt nb_data = in.size() / (nrows * nrows); Matrix<Real> ret_all_strain(nrows, ncols); Tensor3<Real> all_grad_u(in.storage(), nrows, nrows, nb_data); Tensor3<Real> all_strain(ret_all_strain.storage(), nrows, nrows, nb_data); for (UInt d = 0; d < nb_data; ++d) { Matrix<Real> grad_u = all_grad_u(d); Matrix<Real> strain = all_strain(d); if (spatial_dimension == 2) { if (green_strain) Material::gradUToGreenStrain<2>(grad_u, strain); else Material::gradUToEpsilon<2>(grad_u, strain); } else if (spatial_dimension == 3) { if (green_strain) Material::gradUToGreenStrain<3>(grad_u, strain); else Material::gradUToEpsilon<3>(grad_u, strain); } } return ret_all_strain; } UInt getDim() override { return spatial_dimension * spatial_dimension; }; UInt getNbComponent(UInt /*old_nb_comp*/) override { return this->getDim(); }; }; /* -------------------------------------------------------------------------- */ template <bool green_strain> class ComputePrincipalStrain : public MaterialFunctor, public ComputeFunctor<Vector<Real>, Matrix<Real>> { public: ComputePrincipalStrain(const SolidMechanicsModel & model) : MaterialFunctor(model) {} inline Matrix<Real> func(const Vector<Real> & in, Element /*global_element_id*/) override { UInt nrows = spatial_dimension; UInt nb_data = in.size() / (nrows * nrows); Matrix<Real> ret_all_strain(nrows, nb_data); Tensor3<Real> all_grad_u(in.storage(), nrows, nrows, nb_data); Matrix<Real> strain(nrows, nrows); for (UInt d = 0; d < nb_data; ++d) { Matrix<Real> grad_u = all_grad_u(d); if (spatial_dimension == 2) { if (green_strain) Material::gradUToGreenStrain<2>(grad_u, strain); else Material::gradUToEpsilon<2>(grad_u, strain); } else if (spatial_dimension == 3) { if (green_strain) Material::gradUToGreenStrain<3>(grad_u, strain); else Material::gradUToEpsilon<3>(grad_u, strain); } Vector<Real> principal_strain(ret_all_strain(d)); strain.eig(principal_strain); } return ret_all_strain; } UInt getDim() override { return spatial_dimension; }; UInt getNbComponent(UInt /*old_nb_comp*/) override { return this->getDim(); }; }; /* -------------------------------------------------------------------------- */ class ComputeVonMisesStress : public MaterialFunctor, public ComputeFunctor<Vector<Real>, Vector<Real>> { public: ComputeVonMisesStress(const SolidMechanicsModel & model) : MaterialFunctor(model) {} inline Vector<Real> func(const Vector<Real> & in, Element /*global_element_id*/) override { UInt nrows = spatial_dimension; UInt nb_data = in.size() / (nrows * nrows); Vector<Real> von_mises_stress(nb_data); Matrix<Real> deviatoric_stress(3, 3); for (UInt d = 0; d < nb_data; ++d) { Matrix<Real> cauchy_stress(in.storage() + d * nrows * nrows, nrows, nrows); von_mises_stress(d) = Material::stressToVonMises(cauchy_stress); } return von_mises_stress; } UInt getDim() override { return 1; }; UInt getNbComponent(UInt /*old_nb_comp*/) override { return this->getDim(); }; }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu #endif /* __AKANTU_DUMPER_MATERIAL_PADDERS_HH__ */ diff --git a/src/io/dumper/dumper_nodal_field.hh b/src/io/dumper/dumper_nodal_field.hh index bda109fb0..1b3430204 100644 --- a/src/io/dumper/dumper_nodal_field.hh +++ b/src/io/dumper/dumper_nodal_field.hh @@ -1,249 +1,248 @@ /** * @file dumper_nodal_field.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Oct 26 2012 - * @date last modification: Tue Jan 06 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Description of nodal fields * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_NODAL_FIELD_HH__ #define __AKANTU_DUMPER_NODAL_FIELD_HH__ #include "dumper_field.hh" #include <io_helper.hh> /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ // This represents a iohelper compatible field template <typename T, bool filtered = false, class Container = Array<T>, class Filter = Array<UInt>> class NodalField; /* -------------------------------------------------------------------------- */ template <typename T, class Container, class Filter> class NodalField<T, false, Container, Filter> : public dumper::Field { public: /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ /// associated iterator with any nodal field (non filetered) class iterator : public iohelper::iterator<T, iterator, Vector<T>> { public: iterator(T * vect, UInt offset, UInt n, UInt stride, __attribute__((unused)) const UInt * filter = nullptr) : internal_it(vect), offset(offset), n(n), stride(stride) {} bool operator!=(const iterator & it) const override { return internal_it != it.internal_it; } iterator & operator++() override { internal_it += offset; return *this; }; Vector<T> operator*() override { return Vector<T>(internal_it + stride, n); }; private: T * internal_it; UInt offset, n, stride; }; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ NodalField(const Container & field, UInt n = 0, UInt stride = 0, __attribute__((unused)) const Filter * filter = nullptr) : field(field), n(n), stride(stride), padding(0) { AKANTU_DEBUG_ASSERT(filter == nullptr, "Filter passed to unfiltered NodalField!"); if (n == 0) { this->n = field.getNbComponent() - stride; } } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ void registerToDumper(const std::string & id, iohelper::Dumper & dumper) override { dumper.addNodeDataField(id, *this); } inline iterator begin() { return iterator(field.storage(), field.getNbComponent(), n, stride); } inline iterator end() { return iterator(field.storage() + field.getNbComponent() * field.size(), field.getNbComponent(), n, stride); } bool isHomogeneous() override { return true; } void checkHomogeneity() override { this->homogeneous = true; } virtual UInt getDim() { if (this->padding) return this->padding; else return n; } void setPadding(UInt padding) { this->padding = padding; } UInt size() { return field.size(); } iohelper::DataType getDataType() { return iohelper::getDataType<T>(); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: const Container & field; UInt n, stride; UInt padding; }; /* -------------------------------------------------------------------------- */ template <typename T, class Container, class Filter> class NodalField<T, true, Container, Filter> : public dumper::Field { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: class iterator : public iohelper::iterator<T, iterator, Vector<T>> { public: iterator(T * const vect, UInt _offset, UInt _n, UInt _stride, const UInt * filter) : internal_it(vect), offset(_offset), n(_n), stride(_stride), filter(filter) {} bool operator!=(const iterator & it) const override { return filter != it.filter; } iterator & operator++() override { ++filter; return *this; } Vector<T> operator*() override { return Vector<T>(internal_it + *(filter)*offset + stride, n); } private: T * const internal_it; UInt offset, n, stride; const UInt * filter; }; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ NodalField(const Container & _field, UInt _n = 0, UInt _stride = 0, const Filter * filter = NULL) : field(_field), n(_n), stride(_stride), filter(filter), padding(0) { AKANTU_DEBUG_ASSERT(this->filter != nullptr, "No filter passed to filtered NodalField!"); AKANTU_DEBUG_ASSERT(this->filter->getNbComponent() == 1, "Multi-component filter given to NodalField (" << this->filter->getNbComponent() << " components detected, sould be 1"); if (n == 0) { this->n = field.getNbComponent() - stride; } } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ void registerToDumper(const std::string & id, iohelper::Dumper & dumper) override { dumper.addNodeDataField(id, *this); } inline iterator begin() { return iterator(field.storage(), field.getNbComponent(), n, stride, filter->storage()); } inline iterator end() { return iterator(field.storage(), field.getNbComponent(), n, stride, filter->storage() + filter->size()); } bool isHomogeneous() override { return true; } void checkHomogeneity() override { this->homogeneous = true; } virtual UInt getDim() { if (this->padding) return this->padding; else return n; } void setPadding(UInt padding) { this->padding = padding; } UInt size() { return filter->size(); } iohelper::DataType getDataType() { return iohelper::getDataType<T>(); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: const Container & field; UInt n, stride; const Filter * filter; UInt padding; }; __END_AKANTU_DUMPER__ } // akantu /* -------------------------------------------------------------------------- */ #endif /* __AKANTU_DUMPER_NODAL_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_padding_helper.hh b/src/io/dumper/dumper_padding_helper.hh index 5a9f75fc4..5875ebe35 100644 --- a/src/io/dumper/dumper_padding_helper.hh +++ b/src/io/dumper/dumper_padding_helper.hh @@ -1,132 +1,132 @@ /** * @file dumper_padding_helper.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Jun 19 2017 * * @brief Padding helper for field iterators * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_PADDING_HELPER_HH__ #define __AKANTU_DUMPER_PADDING_HELPER_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_compute.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ class PadderInterface { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PadderInterface() { padding_m = 0; padding_n = 0; } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void setPadding(UInt m, UInt n = 0) { padding_m = m; padding_n = n; } virtual UInt getPaddedDim(UInt nb_data) { return nb_data; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: /// padding informations UInt padding_n, padding_m; }; /* -------------------------------------------------------------------------- */ template <class input_type, class output_type> class PadderGeneric : public ComputeFunctor<input_type, output_type>, public PadderInterface { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PadderGeneric() : PadderInterface() {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: inline output_type pad(const input_type & in, __attribute__((unused)) UInt nb_data) { return in; // trick due to the fact that IOHelper padds the vectors (avoid a // copy of data) } }; /* -------------------------------------------------------------------------- */ template <class T> class PadderGeneric<Vector<T>, Matrix<T>> : public ComputeFunctor<Vector<T>, Matrix<T>>, public PadderInterface { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: inline Matrix<T> pad(const Vector<T> & _in, UInt nrows, UInt ncols, UInt nb_data) { Matrix<T> in(_in.storage(), nrows, ncols); if (padding_m <= nrows && padding_n * nb_data <= ncols) return in; else { Matrix<T> ret(padding_m, padding_n * nb_data); UInt nb_cols_per_data = in.cols() / nb_data; for (UInt d = 0; d < nb_data; ++d) for (UInt i = 0; i < in.rows(); ++i) for (UInt j = 0; j < nb_cols_per_data; ++j) ret(i, j + d * padding_n) = in(i, j + d * nb_cols_per_data); return ret; } } }; /* -------------------------------------------------------------------------- */ } // akantu __END_AKANTU_DUMPER__ #endif /* __AKANTU_DUMPER_PADDING_HELPER_HH__ */ diff --git a/src/io/dumper/dumper_quadrature_point_iterator.hh b/src/io/dumper/dumper_quadrature_point_iterator.hh index 52156376f..dc970f2e2 100644 --- a/src/io/dumper/dumper_quadrature_point_iterator.hh +++ b/src/io/dumper/dumper_quadrature_point_iterator.hh @@ -1,74 +1,74 @@ /** * @file dumper_quadrature_point_iterator.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Tue Sep 02 2014 - * @date last modification: Thu Sep 17 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Nov 08 2017 * * @brief Description of quadrature point iterator * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_QUADRATURE_POINT_ITERATOR_HH__ #define __AKANTU_DUMPER_QUADRATURE_POINT_ITERATOR_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_elemental_field.hh" namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <typename types> class quadrature_point_iterator : public element_iterator<types, quadrature_point_iterator> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using parent = element_iterator<types, dumper::quadrature_point_iterator>; using data_type = typename types::data_type; using return_type = typename types::return_type; using field_type = typename types::field_type; using array_iterator = typename types::array_iterator; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: quadrature_point_iterator(const field_type & field, const typename field_type::type_iterator & t_it, const typename field_type::type_iterator & t_it_end, const array_iterator & array_it, const array_iterator & array_it_end, const GhostType ghost_type = _not_ghost) : parent(field, t_it, t_it_end, array_it, array_it_end, ghost_type) {} return_type operator*() { return *this->array_it; } }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // namespace akantu #endif /* __AKANTU_DUMPER_QUADRATURE_POINT_ITERATOR_HH__ */ diff --git a/src/io/dumper/dumper_text.cc b/src/io/dumper/dumper_text.cc index ece87f179..acd6603e4 100644 --- a/src/io/dumper/dumper_text.cc +++ b/src/io/dumper/dumper_text.cc @@ -1,113 +1,112 @@ /** * @file dumper_text.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Tue Nov 07 2017 * * @brief implementation of text dumper * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_text.hh" #include "communicator.hh" #include "dumper_nodal_field.hh" #include "mesh.hh" #include <io_helper.hh> namespace akantu { /* -------------------------------------------------------------------------- */ DumperText::DumperText(const std::string & basename, iohelper::TextDumpMode mode, bool parallel) : DumperIOHelper() { AKANTU_DEBUG_IN(); iohelper::DumperText * dumper_text = new iohelper::DumperText(mode); this->dumper = dumper_text; this->setBaseName(basename); this->setParallelContext(parallel); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DumperText::registerMesh(const Mesh & mesh, __attribute__((unused)) UInt spatial_dimension, __attribute__((unused)) const GhostType & ghost_type, __attribute__((unused)) const ElementKind & element_kind) { registerField("position", new dumper::NodalField<Real>(mesh.getNodes())); // in parallel we need node type UInt nb_proc = mesh.getCommunicator().getNbProc(); if (nb_proc > 1) { registerField("nodes_type", new dumper::NodalField<NodeType>(mesh.getNodesType())); } } /* -------------------------------------------------------------------------- */ void DumperText::registerFilteredMesh( const Mesh & mesh, __attribute__((unused)) const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, __attribute__((unused)) UInt spatial_dimension, __attribute__((unused)) const GhostType & ghost_type, __attribute__((unused)) const ElementKind & element_kind) { registerField("position", new dumper::NodalField<Real, true>( mesh.getNodes(), 0, 0, &nodes_filter)); // in parallel we need node type UInt nb_proc = mesh.getCommunicator().getNbProc(); if (nb_proc > 1) { registerField("nodes_type", new dumper::NodalField<NodeType, true>( mesh.getNodesType(), 0, 0, &nodes_filter)); } } /* -------------------------------------------------------------------------- */ void DumperText::setBaseName(const std::string & basename) { AKANTU_DEBUG_IN(); DumperIOHelper::setBaseName(basename); static_cast<iohelper::DumperText *>(this->dumper) ->setDataSubDirectory(this->filename + "-DataFiles"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DumperText::setPrecision(UInt prec) { AKANTU_DEBUG_IN(); static_cast<iohelper::DumperText *>(this->dumper)->setPrecision(prec); AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/io/dumper/dumper_text.hh b/src/io/dumper/dumper_text.hh index d8e253b31..e7d1ce990 100644 --- a/src/io/dumper/dumper_text.hh +++ b/src/io/dumper/dumper_text.hh @@ -1,88 +1,87 @@ /** * @file dumper_text.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief to dump into a text file * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_iohelper.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DUMPER_TEXT_HH__ #define __AKANTU_DUMPER_TEXT_HH__ /* -------------------------------------------------------------------------- */ #include <io_helper.hh> /* -------------------------------------------------------------------------- */ namespace akantu { class DumperText : public DumperIOHelper { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DumperText(const std::string & basename = "dumper_text", iohelper::TextDumpMode mode = iohelper::_tdm_space, bool parallel = true); ~DumperText() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void registerMesh(const Mesh & mesh, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) override; void registerFilteredMesh( const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_not_defined) override; void setBaseName(const std::string & basename) override; private: void registerNodeTypeField(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: void setPrecision(UInt prec); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; } // akantu #endif /* __AKANTU_DUMPER_TEXT_HH__ */ diff --git a/src/io/dumper/dumper_type_traits.hh b/src/io/dumper/dumper_type_traits.hh index e2f8edf3c..c7f688a8a 100644 --- a/src/io/dumper/dumper_type_traits.hh +++ b/src/io/dumper/dumper_type_traits.hh @@ -1,90 +1,90 @@ /** * @file dumper_type_traits.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Mon Sep 21 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Type traits for field properties * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_TYPE_TRAITS_HH__ #define __AKANTU_DUMPER_TYPE_TRAITS_HH__ /* -------------------------------------------------------------------------- */ #include "element_type_map.hh" #include "element_type_map_filter.hh" /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template <class data, class ret, class field> struct TypeTraits { //! the stored data (real, int, uint, ...) using data_type = data; //! the type returned by the operator * using return_type = ret; //! the field type (ElementTypeMap or ElementTypeMapFilter) using field_type = field; //! the type over which we iterate using it_type = typename field_type::type; //! the type of array (Array<T> or ArrayFilter<T>) using array_type = typename field_type::array_type; //! the iterator over the array using array_iterator = typename array_type::const_vector_iterator; }; /* -------------------------------------------------------------------------- */ // specialization for the case in which input and output types are the same template <class T, template <class> class ret, bool filtered> struct SingleType : public TypeTraits<T, ret<T>, ElementTypeMapArray<T>> {}; /* -------------------------------------------------------------------------- */ // same as before but for filtered data template <class T, template <class> class ret> struct SingleType<T, ret, true> : public TypeTraits<T, ret<T>, ElementTypeMapArrayFilter<T>> {}; /* -------------------------------------------------------------------------- */ // specialization for the case in which input and output types are different template <class it_type, class data_type, template <class> class ret, bool filtered> struct DualType : public TypeTraits<data_type, ret<data_type>, ElementTypeMapArray<it_type>> {}; /* -------------------------------------------------------------------------- */ // same as before but for filtered data template <class it_type, class data_type, template <class> class ret> struct DualType<it_type, data_type, ret, true> : public TypeTraits<data_type, ret<data_type>, ElementTypeMapArrayFilter<it_type>> {}; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu /* -------------------------------------------------------------------------- */ #endif /* __AKANTU_DUMPER_TYPE_TRAITS_HH__ */ diff --git a/src/io/dumper/dumper_variable.hh b/src/io/dumper/dumper_variable.hh index 5d322273b..7ff1228b6 100644 --- a/src/io/dumper/dumper_variable.hh +++ b/src/io/dumper/dumper_variable.hh @@ -1,119 +1,120 @@ /** * @file dumper_variable.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Tue Jun 04 2013 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief template of variable * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include <type_traits> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DUMPER_IOHELPER_TMPL_VARIABLE_HH__ #define __AKANTU_DUMPER_IOHELPER_TMPL_VARIABLE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { namespace dumper { /* -------------------------------------------------------------------------- */ /// Variable interface class VariableBase { public: VariableBase() = default; virtual ~VariableBase() = default; virtual void registerToDumper(const std::string & id, iohelper::Dumper & dumper) = 0; }; /* -------------------------------------------------------------------------- */ template <typename T, bool is_scal = std::is_arithmetic<T>::value> class Variable : public VariableBase { public: Variable(const T & t) : vari(t) {} void registerToDumper(const std::string & id, iohelper::Dumper & dumper) override { dumper.addVariable(id, *this); } const T & operator[](UInt i) const { return vari[i]; } UInt getDim() { return vari.size(); } iohelper::DataType getDataType() { return iohelper::getDataType<T>(); } protected: const T & vari; }; /* -------------------------------------------------------------------------- */ template <typename T> class Variable<Vector<T>, false> : public VariableBase { public: Variable(const Vector<T> & t) : vari(t) {} void registerToDumper(const std::string & id, iohelper::Dumper & dumper) override { dumper.addVariable(id, *this); } const T & operator[](UInt i) const { return vari[i]; } UInt getDim() { return vari.size(); } iohelper::DataType getDataType() { return iohelper::getDataType<T>(); } protected: const Vector<T> & vari; }; /* -------------------------------------------------------------------------- */ template <typename T> class Variable<T, true> : public VariableBase { public: Variable(const T & t) : vari(t) {} void registerToDumper(const std::string & id, iohelper::Dumper & dumper) override { dumper.addVariable(id, *this); } const T & operator[](__attribute__((unused)) UInt i) const { return vari; } UInt getDim() { return 1; } iohelper::DataType getDataType() { return iohelper::getDataType<T>(); } protected: const T & vari; }; } // namespace dumper } // namespace akantu #endif /* __AKANTU_DUMPER_IOHELPER_TMPL_VARIABLE_HH__ */ diff --git a/src/io/mesh_io.cc b/src/io/mesh_io.cc index cdc56a716..23e96bb8a 100644 --- a/src/io/mesh_io.cc +++ b/src/io/mesh_io.cc @@ -1,148 +1,147 @@ /** * @file mesh_io.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Mon Jun 01 2015 + * @date last modification: Thu Feb 01 2018 * * @brief common part for all mesh io classes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "aka_common.hh" #include "aka_iterators.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MeshIO::MeshIO() { canReadSurface = false; canReadExtendedData = false; } /* -------------------------------------------------------------------------- */ MeshIO::~MeshIO() = default; /* -------------------------------------------------------------------------- */ std::unique_ptr<MeshIO> MeshIO::getMeshIO(const std::string & filename, const MeshIOType & type) { MeshIOType t = type; if (type == _miot_auto) { std::string::size_type idx = filename.rfind('.'); std::string ext; if (idx != std::string::npos) { ext = filename.substr(idx + 1); } if (ext == "msh") { t = _miot_gmsh; } else if (ext == "diana") { t = _miot_diana; } else if (ext == "inp") { t = _miot_abaqus; } else AKANTU_EXCEPTION("Cannot guess the type of file of " << filename << " (ext " << ext << "). " << "Please provide the MeshIOType to the read function"); } switch (t) { case _miot_gmsh: return std::make_unique<MeshIOMSH>(); #if defined(AKANTU_STRUCTURAL_MECHANICS) case _miot_gmsh_struct: return std::make_unique<MeshIOMSHStruct>(); #endif case _miot_diana: return std::make_unique<MeshIODiana>(); case _miot_abaqus: return std::make_unique<MeshIOAbaqus>(); default: return nullptr; } } /* -------------------------------------------------------------------------- */ void MeshIO::read(const std::string & filename, Mesh & mesh, const MeshIOType & type) { std::unique_ptr<MeshIO> mesh_io = getMeshIO(filename, type); mesh_io->read(filename, mesh); } /* -------------------------------------------------------------------------- */ void MeshIO::write(const std::string & filename, Mesh & mesh, const MeshIOType & type) { std::unique_ptr<MeshIO> mesh_io = getMeshIO(filename, type); mesh_io->write(filename, mesh); } /* -------------------------------------------------------------------------- */ void MeshIO::constructPhysicalNames(const std::string & tag_name, Mesh & mesh) { if (!phys_name_map.empty()) { for (Mesh::type_iterator type_it = mesh.firstType(); type_it != mesh.lastType(); ++type_it) { auto & name_vec = mesh.getDataPointer<std::string>("physical_names", *type_it); const auto & tags_vec = mesh.getData<UInt>(tag_name, *type_it); for (auto pair : zip(tags_vec, name_vec)) { auto tag = std::get<0>(pair); auto & name = std::get<1>(pair); auto map_it = phys_name_map.find(tag); if (map_it == phys_name_map.end()) { std::stringstream sstm; sstm << tag; name = sstm.str(); } else { name = map_it->second; } } } } } /* -------------------------------------------------------------------------- */ void MeshIO::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; if (phys_name_map.size()) { stream << space << "Physical map:" << std::endl; for (auto & pair : phys_name_map) { stream << space << pair.first << ": " << pair.second << std::endl; } } } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/io/mesh_io.hh b/src/io/mesh_io.hh index 5e4860613..5ff6aa2f8 100644 --- a/src/io/mesh_io.hh +++ b/src/io/mesh_io.hh @@ -1,118 +1,117 @@ /** * @file mesh_io.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Mon Jun 01 2015 + * @date last modification: Wed Aug 09 2017 * * @brief interface of a mesh io class, reader and writer * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_IO_HH__ #define __AKANTU_MESH_IO_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class MeshIO { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshIO(); virtual ~MeshIO(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void read(const std::string & filename, Mesh & mesh, const MeshIOType & type); void write(const std::string & filename, Mesh & mesh, const MeshIOType & type); /// read a mesh from the file virtual void read(__attribute__((unused)) const std::string & filename, __attribute__((unused)) Mesh & mesh) {} /// write a mesh to a file virtual void write(__attribute__((unused)) const std::string & filename, __attribute__((unused)) const Mesh & mesh) {} /// function to request the manual construction of the physical names maps virtual void constructPhysicalNames(const std::string & tag_name, Mesh & mesh); /// method to permit to be printed to a generic stream virtual void printself(std::ostream & stream, int indent = 0) const; /// static contruction of a meshio object static std::unique_ptr<MeshIO> getMeshIO(const std::string & filename, const MeshIOType & type); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: std::map<UInt, std::string> & getPhysicalNameMap() { return phys_name_map; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: bool canReadSurface; bool canReadExtendedData; /// correspondance between a tag and physical names (if applicable) std::map<UInt, std::string> phys_name_map; }; /* -------------------------------------------------------------------------- */ inline std::ostream & operator<<(std::ostream & stream, const MeshIO & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ } // namespace akantu #include "mesh_io_abaqus.hh" #include "mesh_io_diana.hh" #include "mesh_io_msh.hh" #if defined(AKANTU_STRUCTURAL_MECHANICS) #include "mesh_io_msh_struct.hh" #endif #endif /* __AKANTU_MESH_IO_HH__ */ diff --git a/src/io/mesh_io/mesh_io_abaqus.cc b/src/io/mesh_io/mesh_io_abaqus.cc index a9f7714b4..fd16133b7 100644 --- a/src/io/mesh_io/mesh_io_abaqus.cc +++ b/src/io/mesh_io/mesh_io_abaqus.cc @@ -1,475 +1,475 @@ /** * @file mesh_io_abaqus.cc * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Fri Dec 11 2015 + * @date last modification: Tue Feb 20 2018 * * @brief read a mesh from an abaqus input file * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ // std library header files #include <fstream> // akantu header files #include "mesh.hh" #include "mesh_io_abaqus.hh" #include "mesh_utils.hh" #include "element_group.hh" #include "node_group.hh" #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it // is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40600 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif /* -------------------------------------------------------------------------- */ #include <boost/config/warning_disable.hpp> #include <boost/spirit/include/phoenix.hpp> #include <boost/spirit/include/qi.hpp> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MeshIOAbaqus::MeshIOAbaqus() = default; /* -------------------------------------------------------------------------- */ MeshIOAbaqus::~MeshIOAbaqus() = default; /* -------------------------------------------------------------------------- */ namespace spirit = boost::spirit; namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace lbs = boost::spirit::qi::labels; namespace phx = boost::phoenix; /* -------------------------------------------------------------------------- */ void element_read(Mesh & mesh, const ElementType & type, UInt id, const std::vector<Int> & conn, const std::map<UInt, UInt> & nodes_mapping, std::map<UInt, Element> & elements_mapping) { Vector<UInt> tmp_conn(Mesh::getNbNodesPerElement(type)); AKANTU_DEBUG_ASSERT(conn.size() == tmp_conn.size(), "The nodes in the Abaqus file have too many coordinates" << " for the mesh you try to fill."); mesh.addConnectivityType(type); Array<UInt> & connectivity = mesh.getConnectivity(type); UInt i = 0; for (auto it = conn.begin(); it != conn.end(); ++it) { auto nit = nodes_mapping.find(*it); AKANTU_DEBUG_ASSERT(nit != nodes_mapping.end(), "There is an unknown node in the connectivity."); tmp_conn[i++] = nit->second; } Element el{type, connectivity.size(), _not_ghost}; elements_mapping[id] = el; connectivity.push_back(tmp_conn); } void node_read(Mesh & mesh, UInt id, const std::vector<Real> & pos, std::map<UInt, UInt> & nodes_mapping) { Vector<Real> tmp_pos(mesh.getSpatialDimension()); UInt i = 0; for (auto it = pos.begin(); it != pos.end() || i < mesh.getSpatialDimension(); ++it) tmp_pos[i++] = *it; nodes_mapping[id] = mesh.getNbNodes(); mesh.getNodes().push_back(tmp_pos); } /* ------------------------------------------------------------------------ */ void add_element_to_group(ElementGroup * el_grp, UInt element, const std::map<UInt, Element> & elements_mapping) { auto eit = elements_mapping.find(element); AKANTU_DEBUG_ASSERT(eit != elements_mapping.end(), "There is an unknown element (" << element << ") in the in the ELSET " << el_grp->getName() << "."); el_grp->add(eit->second, true, false); } ElementGroup * element_group_create(Mesh & mesh, const ID & name) { auto eg_it = mesh.element_group_find(name); if (eg_it != mesh.element_group_end()) { return eg_it->second; } else { return &mesh.createElementGroup(name, _all_dimensions); } } NodeGroup * node_group_create(Mesh & mesh, const ID & name) { auto ng_it = mesh.node_group_find(name); if (ng_it != mesh.node_group_end()) { return ng_it->second; } else { return &mesh.createNodeGroup(name, mesh.getSpatialDimension()); } } void add_node_to_group(NodeGroup * node_grp, UInt node, const std::map<UInt, UInt> & nodes_mapping) { auto nit = nodes_mapping.find(node); AKANTU_DEBUG_ASSERT(nit != nodes_mapping.end(), "There is an unknown node in the in the NSET " << node_grp->getName() << "."); node_grp->add(nit->second, false); } void optimize_group(NodeGroup * grp) { grp->optimize(); } void optimize_element_group(ElementGroup * grp) { grp->optimize(); } /* -------------------------------------------------------------------------- */ template <class Iterator> struct AbaqusSkipper : qi::grammar<Iterator> { AbaqusSkipper() : AbaqusSkipper::base_type(skip, "abaqus_skipper") { /* clang-format off */ skip = (ascii::space - spirit::eol) | "**" >> *(qi::char_ - spirit::eol) >> spirit::eol ; /* clang-format on */ } qi::rule<Iterator> skip; }; /* -------------------------------------------------------------------------- */ template <class Iterator, typename Skipper = AbaqusSkipper<Iterator>> struct AbaqusMeshGrammar : qi::grammar<Iterator, void(), Skipper> { public: AbaqusMeshGrammar(Mesh & mesh) : AbaqusMeshGrammar::base_type(start, "abaqus_mesh_reader"), mesh(mesh) { /* clang-format off */ start = *( (qi::char_('*') > ( (qi::no_case[ qi::lit("node output") ] > any_section) | (qi::no_case[ qi::lit("element output") ] > any_section) | (qi::no_case[ qi::lit("node") ] > nodes) | (qi::no_case[ qi::lit("element") ] > elements) | (qi::no_case[ qi::lit("heading") ] > header) | (qi::no_case[ qi::lit("elset") ] > elements_set) | (qi::no_case[ qi::lit("nset") ] > nodes_set) | (qi::no_case[ qi::lit("material") ] > material) | (keyword > any_section) ) ) | spirit::eol ) ; header = spirit::eol > *any_line ; nodes = *(qi::char_(',') >> option) >> spirit::eol >> *( (qi::int_ > node_position) [ phx::bind(&node_read, phx::ref(mesh), lbs::_1, lbs::_2, phx::ref(abaqus_nodes_to_akantu)) ] >> spirit::eol ) ; elements = ( ( qi::char_(',') >> qi::no_case[qi::lit("type")] >> '=' >> abaqus_element_type [ lbs::_a = lbs::_1 ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol >> *( (qi::int_ > connectivity) [ phx::bind(&element_read, phx::ref(mesh), lbs::_a, lbs::_1, lbs::_2, phx::cref(abaqus_nodes_to_akantu), phx::ref(abaqus_elements_to_akantu)) ] >> spirit::eol ) ; elements_set = ( ( ( qi::char_(',') >> qi::no_case[ qi::lit("elset") ] >> '=' >> value [ lbs::_a = phx::bind<ElementGroup *>(&element_group_create, phx::ref(mesh), lbs::_1) ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol >> qi::skip (qi::char_(',') | qi::space) [ +(qi::int_ [ phx::bind(&add_element_to_group, lbs::_a, lbs::_1, phx::cref(abaqus_elements_to_akantu) ) ] ) ] ) [ phx::bind(&optimize_element_group, lbs::_a) ] ; nodes_set = ( ( ( qi::char_(',') >> qi::no_case[ qi::lit("nset") ] >> '=' >> value [ lbs::_a = phx::bind<NodeGroup *>(&node_group_create, phx::ref(mesh), lbs::_1) ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol >> qi::skip (qi::char_(',') | qi::space) [ +(qi::int_ [ phx::bind(&add_node_to_group, lbs::_a, lbs::_1, phx::cref(abaqus_nodes_to_akantu) ) ] ) ] ) [ phx::bind(&optimize_group, lbs::_a) ] ; material = ( ( qi::char_(',') >> qi::no_case[ qi::lit("name") ] >> '=' >> value [ phx::push_back(phx::ref(material_names), lbs::_1) ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol; ; node_position = +(qi::char_(',') > real [ phx::push_back(lbs::_val, lbs::_1) ]) ; connectivity = +(qi::char_(',') > qi::int_ [ phx::push_back(lbs::_val, lbs::_1) ]) ; any_section = *(qi::char_(',') >> option) > spirit::eol > *any_line ; any_line = *(qi::char_ - spirit::eol - qi::char_('*')) >> spirit::eol ; keyword = qi::lexeme[ +(qi::char_ - (qi::char_('*') | spirit::eol)) ] ; option = key > -( '=' >> value ); key = qi::char_("a-zA-Z_") >> *(qi::char_("a-zA-Z_0-9") | qi::char_('-')) ; value = key.alias() ; BOOST_SPIRIT_DEBUG_NODE(start); abaqus_element_type.add #if defined(AKANTU_STRUCTURAL_MECHANICS) ("BE21" , _bernoulli_beam_2) ("BE31" , _bernoulli_beam_3) #endif ("T3D2" , _segment_2) // Gmsh generates this elements ("T3D3" , _segment_3) // Gmsh generates this elements ("CPE3" , _triangle_3) ("CPS3" , _triangle_3) ("DC2D3" , _triangle_3) ("CPE6" , _triangle_6) ("CPS6" , _triangle_6) ("DC2D6" , _triangle_6) ("CPE4" , _quadrangle_4) ("CPS4" , _quadrangle_4) ("DC2D4" , _quadrangle_4) ("CPE8" , _quadrangle_8) ("CPS8" , _quadrangle_8) ("DC2D8" , _quadrangle_8) ("C3D4" , _tetrahedron_4) ("DC3D4" , _tetrahedron_4) ("C3D8" , _hexahedron_8) ("C3D8R" , _hexahedron_8) ("DC3D8" , _hexahedron_8) ("C3D10" , _tetrahedron_10) ("DC3D10", _tetrahedron_10); #if !defined(AKANTU_NDEBUG) && defined(AKANTU_CORE_CXX_11) qi::on_error<qi::fail>(start, error_handler(lbs::_4, lbs::_3, lbs::_2)); #endif start .name("abaqus-start-rule"); connectivity .name("abaqus-connectivity"); node_position .name("abaqus-nodes-position"); nodes .name("abaqus-nodes"); any_section .name("abaqus-any_section"); header .name("abaqus-header"); material .name("abaqus-material"); elements .name("abaqus-elements"); elements_set .name("abaqus-elements-set"); nodes_set .name("abaqus-nodes-set"); key .name("abaqus-key"); value .name("abaqus-value"); option .name("abaqus-option"); keyword .name("abaqus-keyword"); any_line .name("abaqus-any-line"); abaqus_element_type.name("abaqus-element-type"); /* clang-format on */ } public: AKANTU_GET_MACRO(MaterialNames, material_names, const std::vector<std::string> &); /* ------------------------------------------------------------------------ */ /* Rules */ /* ------------------------------------------------------------------------ */ private: qi::rule<Iterator, void(), Skipper> start; qi::rule<Iterator, std::vector<int>(), Skipper> connectivity; qi::rule<Iterator, std::vector<Real>(), Skipper> node_position; qi::rule<Iterator, void(), Skipper> nodes, any_section, header, material; qi::rule<Iterator, void(), qi::locals<ElementType>, Skipper> elements; qi::rule<Iterator, void(), qi::locals<ElementGroup *>, Skipper> elements_set; qi::rule<Iterator, void(), qi::locals<NodeGroup *>, Skipper> nodes_set; qi::rule<Iterator, std::string(), Skipper> key, value, option, keyword, any_line; qi::real_parser<Real, qi::real_policies<Real>> real; qi::symbols<char, ElementType> abaqus_element_type; /* ------------------------------------------------------------------------ */ /* Mambers */ /* ------------------------------------------------------------------------ */ private: /// reference to the mesh to read Mesh & mesh; /// correspondance between the numbering of nodes in the abaqus file and in /// the akantu mesh std::map<UInt, UInt> abaqus_nodes_to_akantu; /// correspondance between the element number in the abaqus file and the /// Element in the akantu mesh std::map<UInt, Element> abaqus_elements_to_akantu; /// list of the material names std::vector<std::string> material_names; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void MeshIOAbaqus::read(const std::string & filename, Mesh & mesh) { namespace spirit = boost::spirit; namespace qi = boost::spirit::qi; namespace lbs = boost::spirit::qi::labels; namespace ascii = boost::spirit::ascii; namespace phx = boost::phoenix; std::ifstream infile; infile.open(filename.c_str()); if (!infile.good()) { AKANTU_ERROR("Cannot open file " << filename); } std::string storage; // We will read the contents here. infile.unsetf(std::ios::skipws); // No white space skipping! std::copy(std::istream_iterator<char>(infile), std::istream_iterator<char>(), std::back_inserter(storage)); using iterator_t = std::string::const_iterator; using skipper = AbaqusSkipper<iterator_t>; using grammar = AbaqusMeshGrammar<iterator_t, skipper>; grammar g(mesh); skipper ws; iterator_t iter = storage.begin(); iterator_t end = storage.end(); qi::phrase_parse(iter, end, g, ws); MeshAccessor mesh_accessor(mesh); for (auto & mat_name : g.getMaterialNames()) { auto eg_it = mesh.element_group_find(mat_name); auto & eg = *eg_it->second; if (eg_it != mesh.element_group_end()) { for (auto & type : eg.elementTypes()) { Array<std::string> & abaqus_material = mesh_accessor.getData<std::string>("abaqus_material", type); for (auto elem : eg.getElements(type)) { abaqus_material(elem) = mat_name; } } } } mesh_accessor.setNbGlobalNodes(mesh.getNodes().size()); MeshUtils::fillElementToSubElementsData(mesh); } } // namespace akantu diff --git a/src/io/mesh_io/mesh_io_abaqus.hh b/src/io/mesh_io/mesh_io_abaqus.hh index 5feea6314..305eb2d93 100644 --- a/src/io/mesh_io/mesh_io_abaqus.hh +++ b/src/io/mesh_io/mesh_io_abaqus.hh @@ -1,60 +1,59 @@ /** * @file mesh_io_abaqus.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sun Sep 26 2010 - * @date last modification: Tue Jun 30 2015 + * @date last modification: Wed Nov 08 2017 * * @brief read a mesh from an abaqus input file * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_accessor.hh" #include "mesh_io.hh" #ifndef __AKANTU_MESH_IO_ABAQUS_HH__ #define __AKANTU_MESH_IO_ABAQUS_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ class MeshIOAbaqus : public MeshIO { public: MeshIOAbaqus(); ~MeshIOAbaqus() override; /// read a mesh from the file void read(const std::string & filename, Mesh & mesh) override; /// write a mesh to a file // virtual void write(const std::string & filename, const Mesh & mesh); private: /// correspondence between msh element types and akantu element types std::map<std::string, ElementType> _abaqus_to_akantu_element_types; }; } // akantu #endif /* __AKANTU_MESH_IO_ABAQUS_HH__ */ diff --git a/src/io/mesh_io/mesh_io_diana.cc b/src/io/mesh_io/mesh_io_diana.cc index 634226ac0..80a3bc957 100644 --- a/src/io/mesh_io/mesh_io_diana.cc +++ b/src/io/mesh_io/mesh_io_diana.cc @@ -1,602 +1,601 @@ /** * @file mesh_io_diana.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Alodie Schneuwly <alodie.schneuwly@epfl.ch> * * @date creation: Sat Mar 26 2011 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Tue Feb 20 2018 * * @brief handles diana meshes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include <fstream> #include <iostream> /* -------------------------------------------------------------------------- */ #include "element_group.hh" #include "mesh_io_diana.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <string.h> /* -------------------------------------------------------------------------- */ #include <stdio.h> namespace akantu { /* -------------------------------------------------------------------------- */ /* Methods Implentations */ /* -------------------------------------------------------------------------- */ MeshIODiana::MeshIODiana() { canReadSurface = true; canReadExtendedData = true; _diana_to_akantu_element_types["T9TM"] = _triangle_3; _diana_to_akantu_element_types["CT6CM"] = _triangle_6; _diana_to_akantu_element_types["Q12TM"] = _quadrangle_4; _diana_to_akantu_element_types["CQ8CM"] = _quadrangle_8; _diana_to_akantu_element_types["TP18L"] = _pentahedron_6; _diana_to_akantu_element_types["CTP45"] = _pentahedron_15; _diana_to_akantu_element_types["TE12L"] = _tetrahedron_4; _diana_to_akantu_element_types["HX24L"] = _hexahedron_8; _diana_to_akantu_element_types["CHX60"] = _hexahedron_20; _diana_to_akantu_mat_prop["YOUNG"] = "E"; _diana_to_akantu_mat_prop["DENSIT"] = "rho"; _diana_to_akantu_mat_prop["POISON"] = "nu"; std::map<std::string, ElementType>::iterator it; for (it = _diana_to_akantu_element_types.begin(); it != _diana_to_akantu_element_types.end(); ++it) { UInt nb_nodes = Mesh::getNbNodesPerElement(it->second); auto * tmp = new UInt[nb_nodes]; for (UInt i = 0; i < nb_nodes; ++i) { tmp[i] = i; } switch (it->second) { case _tetrahedron_10: tmp[8] = 9; tmp[9] = 8; break; case _pentahedron_15: tmp[0] = 2; tmp[1] = 8; tmp[2] = 0; tmp[3] = 6; tmp[4] = 1; tmp[5] = 7; tmp[6] = 11; tmp[7] = 9; tmp[8] = 10; tmp[9] = 5; tmp[10] = 14; tmp[11] = 3; tmp[12] = 12; tmp[13] = 4; tmp[14] = 13; break; case _hexahedron_20: tmp[0] = 5; tmp[1] = 16; tmp[2] = 4; tmp[3] = 19; tmp[4] = 7; tmp[5] = 18; tmp[6] = 6; tmp[7] = 17; tmp[8] = 13; tmp[9] = 12; tmp[10] = 15; tmp[11] = 14; tmp[12] = 1; tmp[13] = 8; tmp[14] = 0; tmp[15] = 11; tmp[16] = 3; tmp[17] = 10; tmp[18] = 2; tmp[19] = 9; break; default: // nothing to change break; } _read_order[it->second] = tmp; } } /* -------------------------------------------------------------------------- */ MeshIODiana::~MeshIODiana() = default; /* -------------------------------------------------------------------------- */ inline void my_getline(std::ifstream & infile, std::string & line) { std::getline(infile, line); // read the line size_t pos = line.find('\r'); /// remove the extra \r if needed line = line.substr(0, pos); } /* -------------------------------------------------------------------------- */ void MeshIODiana::read(const std::string & filename, Mesh & mesh) { AKANTU_DEBUG_IN(); MeshAccessor mesh_accessor(mesh); std::ifstream infile; infile.open(filename.c_str()); std::string line; UInt first_node_number = std::numeric_limits<UInt>::max(); diana_element_number_to_elements.clear(); if (!infile.good()) { AKANTU_ERROR("Cannot open file " << filename); } while (infile.good()) { my_getline(infile, line); /// read all nodes if (line == "'COORDINATES'") { line = readCoordinates(infile, mesh, first_node_number); } /// read all elements if (line == "'ELEMENTS'") { line = readElements(infile, mesh, first_node_number); } /// read the material properties and write a .dat file if (line == "'MATERIALS'") { line = readMaterial(infile, filename); } /// read the material properties and write a .dat file if (line == "'GROUPS'") { line = readGroups(infile, mesh, first_node_number); } } infile.close(); mesh_accessor.setNbGlobalNodes(mesh.getNbNodes()); MeshUtils::fillElementToSubElementsData(mesh); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshIODiana::write(__attribute__((unused)) const std::string & filename, __attribute__((unused)) const Mesh & mesh) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ std::string MeshIODiana::readCoordinates(std::ifstream & infile, Mesh & mesh, UInt & first_node_number) { AKANTU_DEBUG_IN(); MeshAccessor mesh_accessor(mesh); Array<Real> & nodes = mesh_accessor.getNodes(); std::string line; UInt index; Vector<Real> coord(3); do { my_getline(infile, line); if ("'ELEMENTS'" == line) break; std::stringstream sstr_node(line); sstr_node >> index >> coord(0) >> coord(1) >> coord(2); first_node_number = first_node_number < index ? first_node_number : index; nodes.push_back(coord); } while (true); AKANTU_DEBUG_OUT(); return line; } /* -------------------------------------------------------------------------- */ UInt MeshIODiana::readInterval(std::stringstream & line, std::set<UInt> & interval) { UInt first; line >> first; if (line.fail()) { return 0; } interval.insert(first); UInt second; int dash; dash = line.get(); if (dash == '-') { line >> second; interval.insert(second); return 2; } if (line.fail()) line.clear(std::ios::eofbit); // in case of get at end of the line else line.unget(); return 1; } /* -------------------------------------------------------------------------- */ std::string MeshIODiana::readGroups(std::ifstream & infile, Mesh & mesh, UInt first_node_number) { AKANTU_DEBUG_IN(); std::string line; my_getline(infile, line); bool reading_nodes_group = false; while (line != "'SUPPORTS'") { if (line == "NODES") { reading_nodes_group = true; my_getline(infile, line); } if (line == "ELEMEN") { reading_nodes_group = false; my_getline(infile, line); } auto * str = new std::stringstream(line); UInt id; std::string name; char c; *str >> id >> name >> c; auto * list_ids = new Array<UInt>(0, 1, name); UInt s = 1; bool end = false; while (!end) { while (!str->eof() && s != 0) { std::set<UInt> interval; s = readInterval(*str, interval); auto it = interval.begin(); if (s == 1) list_ids->push_back(*it); if (s == 2) { UInt first = *it; ++it; UInt second = *it; for (UInt i = first; i <= second; ++i) { list_ids->push_back(i); } } } if (str->fail()) end = true; else { my_getline(infile, line); delete str; str = new std::stringstream(line); } } delete str; if (reading_nodes_group) { NodeGroup & ng = mesh.createNodeGroup(name); for (UInt i = 0; i < list_ids->size(); ++i) { UInt node = (*list_ids)(i)-first_node_number; ng.add(node, false); } delete list_ids; } else { ElementGroup & eg = mesh.createElementGroup(name); for (UInt i = 0; i < list_ids->size(); ++i) { Element & elem = diana_element_number_to_elements[(*list_ids)(i)]; if (elem.type != _not_defined) eg.add(elem, false, false); } eg.optimize(); delete list_ids; } my_getline(infile, line); } AKANTU_DEBUG_OUT(); return line; } /* -------------------------------------------------------------------------- */ std::string MeshIODiana::readElements(std::ifstream & infile, Mesh & mesh, UInt first_node_number) { AKANTU_DEBUG_IN(); std::string line; my_getline(infile, line); if ("CONNECTIVITY" == line) { line = readConnectivity(infile, mesh, first_node_number); } /// read the line corresponding to the materials if ("MATERIALS" == line) { line = readMaterialElement(infile, mesh); } AKANTU_DEBUG_OUT(); return line; } /* -------------------------------------------------------------------------- */ std::string MeshIODiana::readConnectivity(std::ifstream & infile, Mesh & mesh, UInt first_node_number) { AKANTU_DEBUG_IN(); MeshAccessor mesh_accessor(mesh); Int index; std::string lline; std::string diana_type; ElementType akantu_type, akantu_type_old = _not_defined; Array<UInt> * connectivity = nullptr; UInt node_per_element = 0; Element elem; UInt * read_order = nullptr; while (true) { my_getline(infile, lline); // std::cerr << lline << std::endl; std::stringstream sstr_elem(lline); if (lline == "MATERIALS") break; /// traiter les coordonnees sstr_elem >> index; sstr_elem >> diana_type; akantu_type = _diana_to_akantu_element_types[diana_type]; if (akantu_type == _not_defined) continue; if (akantu_type != akantu_type_old) { connectivity = &(mesh_accessor.getConnectivity(akantu_type)); node_per_element = connectivity->getNbComponent(); akantu_type_old = akantu_type; read_order = _read_order[akantu_type]; } Vector<UInt> local_connect(node_per_element); // used if element is written on two lines UInt j_last = 0; for (UInt j = 0; j < node_per_element; ++j) { UInt node_index; sstr_elem >> node_index; // check s'il y a pas plus rien après un certain point if (sstr_elem.fail()) { sstr_elem.clear(); sstr_elem.ignore(); break; } node_index -= first_node_number; local_connect(read_order[j]) = node_index; j_last = j; } // check if element is written in two lines if (j_last != (node_per_element - 1)) { // if this is the case, read on more line my_getline(infile, lline); std::stringstream sstr_elem(lline); for (UInt j = (j_last + 1); j < node_per_element; ++j) { UInt node_index; sstr_elem >> node_index; node_index -= first_node_number; local_connect(read_order[j]) = node_index; } } connectivity->push_back(local_connect); elem.type = akantu_type; elem.element = connectivity->size() - 1; diana_element_number_to_elements[index] = elem; akantu_number_to_diana_number[elem] = index; } AKANTU_DEBUG_OUT(); return lline; } /* -------------------------------------------------------------------------- */ std::string MeshIODiana::readMaterialElement(std::ifstream & infile, Mesh & mesh) { AKANTU_DEBUG_IN(); std::string line; std::stringstream sstr_tag_name; sstr_tag_name << "tag_" << 0; Mesh::type_iterator it = mesh.firstType(); Mesh::type_iterator end = mesh.lastType(); for (; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); mesh.getDataPointer<UInt>("material", *it, _not_ghost, 1) .resize(nb_element); } my_getline(infile, line); while (line != "'MATERIALS'") { line = line.substr(line.find('/') + 1, std::string::npos); // erase the first slash / of the line char tutu[250]; strncpy(tutu, line.c_str(), 250); AKANTU_DEBUG_WARNING("reading line " << line); Array<UInt> temp_id(0, 2); UInt mat; while (true) { std::stringstream sstr_intervals_elements(line); Vector<UInt> id(2); char temp; while (sstr_intervals_elements.good()) { sstr_intervals_elements >> id(0) >> temp >> id(1); // >> "/" >> mat; if (!sstr_intervals_elements.fail()) temp_id.push_back(id); } if (sstr_intervals_elements.fail()) { sstr_intervals_elements.clear(); sstr_intervals_elements.ignore(); sstr_intervals_elements >> mat; break; } my_getline(infile, line); } // loop over elements // UInt * temp_id_val = temp_id.storage(); for (UInt i = 0; i < temp_id.size(); ++i) for (UInt j = temp_id(i, 0); j <= temp_id(i, 1); ++j) { Element & element = diana_element_number_to_elements[j]; if (element.type == _not_defined) continue; UInt elem = element.element; ElementType type = element.type; Array<UInt> & data = mesh.getDataPointer<UInt>("material", type, _not_ghost); data(elem) = mat; } my_getline(infile, line); } AKANTU_DEBUG_OUT(); return line; } /* -------------------------------------------------------------------------- */ std::string MeshIODiana::readMaterial(std::ifstream & infile, const std::string & filename) { AKANTU_DEBUG_IN(); std::stringstream mat_file_name; mat_file_name << "material_" << filename; std::ofstream material_file; material_file.open(mat_file_name.str().c_str()); // mat_file_name.str()); UInt mat_index; std::string line; bool first_mat = true; bool end = false; UInt mat_id = 0; using MatProp = std::map<std::string, Real>; MatProp mat_prop; do { my_getline(infile, line); std::stringstream sstr_material(line); if (("'GROUPS'" == line) || ("'END'" == line)) { if (!mat_prop.empty()) { material_file << "material elastic [" << std::endl; material_file << "\tname = material" << ++mat_id << std::endl; for (auto it = mat_prop.begin(); it != mat_prop.end(); ++it) material_file << "\t" << it->first << " = " << it->second << std::endl; material_file << "]" << std::endl; mat_prop.clear(); } end = true; } else { /// traiter les caractéristiques des matériaux sstr_material >> mat_index; if (!sstr_material.fail()) { if (!first_mat) { if (!mat_prop.empty()) { material_file << "material elastic [" << std::endl; material_file << "\tname = material" << ++mat_id << std::endl; for (auto it = mat_prop.begin(); it != mat_prop.end(); ++it) material_file << "\t" << it->first << " = " << it->second << std::endl; material_file << "]" << std::endl; mat_prop.clear(); } } first_mat = false; } else { sstr_material.clear(); } std::string prop_name; sstr_material >> prop_name; std::map<std::string, std::string>::iterator it; it = _diana_to_akantu_mat_prop.find(prop_name); if (it != _diana_to_akantu_mat_prop.end()) { Real value; sstr_material >> value; mat_prop[it->second] = value; } else { AKANTU_DEBUG_INFO("In material reader, property " << prop_name << "not recognized"); } } } while (!end); AKANTU_DEBUG_OUT(); return line; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/io/mesh_io/mesh_io_diana.hh b/src/io/mesh_io/mesh_io_diana.hh index a5bde0911..fde134690 100644 --- a/src/io/mesh_io/mesh_io_diana.hh +++ b/src/io/mesh_io/mesh_io_diana.hh @@ -1,109 +1,108 @@ /** * @file mesh_io_diana.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Alodie Schneuwly <alodie.schneuwly@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Nov 19 2015 + * @date last modification: Wed Nov 08 2017 * * @brief diana mesh reader description * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_IO_DIANA_HH__ #define __AKANTU_MESH_IO_DIANA_HH__ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" /* -------------------------------------------------------------------------- */ #include <vector> /* -------------------------------------------------------------------------- */ namespace akantu { class MeshIODiana : public MeshIO { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshIODiana(); ~MeshIODiana() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// read a mesh from the file void read(const std::string & filename, Mesh & mesh) override; /// write a mesh to a file void write(const std::string & filename, const Mesh & mesh) override; private: std::string readCoordinates(std::ifstream & infile, Mesh & mesh, UInt & first_node_number); std::string readElements(std::ifstream & infile, Mesh & mesh, UInt first_node_number); std::string readGroups(std::ifstream & infile, Mesh & mesh, UInt first_node_number); std::string readConnectivity(std::ifstream & infile, Mesh & mesh, UInt first_node_number); std::string readMaterialElement(std::ifstream & infile, Mesh & mesh); std::string readMaterial(std::ifstream & infile, const std::string & filename); UInt readInterval(std::stringstream & line, std::set<UInt> & interval); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: std::map<std::string, ElementType> _diana_to_akantu_element_types; std::map<std::string, std::string> _diana_to_akantu_mat_prop; /// order in witch element as to be read, akantu_node_order = /// _read_order[diana_node_order] std::map<ElementType, UInt *> _read_order; std::map<UInt, Element> diana_element_number_to_elements; std::map<Element, UInt> akantu_number_to_diana_number; }; } // akantu #endif /* __AKANTU_MESH_IO_DIANA_HH__ */ diff --git a/src/io/mesh_io/mesh_io_msh.cc b/src/io/mesh_io/mesh_io_msh.cc index 2f160815c..1e50bdaa5 100644 --- a/src/io/mesh_io/mesh_io_msh.cc +++ b/src/io/mesh_io/mesh_io_msh.cc @@ -1,972 +1,971 @@ /** * @file mesh_io_msh.cc * * @author Dana Christen <dana.christen@gmail.com> * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Read/Write for MSH files generated by gmsh * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* ----------------------------------------------------------------------------- Version (Legacy) 1.0 $NOD number-of-nodes node-number x-coord y-coord z-coord ... $ENDNOD $ELM number-of-elements elm-number elm-type reg-phys reg-elem number-of-nodes node-number-list ... $ENDELM ----------------------------------------------------------------------------- Version 2.1 $MeshFormat version-number file-type data-size $EndMeshFormat $Nodes number-of-nodes node-number x-coord y-coord z-coord ... $EndNodes $Elements number-of-elements elm-number elm-type number-of-tags < tag > ... node-number-list ... $EndElements $PhysicalNames number-of-names physical-dimension physical-number "physical-name" ... $EndPhysicalNames $NodeData number-of-string-tags < "string-tag" > ... number-of-real-tags < real-tag > ... number-of-integer-tags < integer-tag > ... node-number value ... ... $EndNodeData $ElementData number-of-string-tags < "string-tag" > ... number-of-real-tags < real-tag > ... number-of-integer-tags < integer-tag > ... elm-number value ... ... $EndElementData $ElementNodeData number-of-string-tags < "string-tag" > ... number-of-real-tags < real-tag > ... number-of-integer-tags < integer-tag > ... elm-number number-of-nodes-per-element value ... ... $ElementEndNodeData ----------------------------------------------------------------------------- elem-type 1: 2-node line. 2: 3-node triangle. 3: 4-node quadrangle. 4: 4-node tetrahedron. 5: 8-node hexahedron. 6: 6-node prism. 7: 5-node pyramid. 8: 3-node second order line 9: 6-node second order triangle 10: 9-node second order quadrangle 11: 10-node second order tetrahedron 12: 27-node second order hexahedron 13: 18-node second order prism 14: 14-node second order pyramid 15: 1-node point. 16: 8-node second order quadrangle 17: 20-node second order hexahedron 18: 15-node second order prism 19: 13-node second order pyramid 20: 9-node third order incomplete triangle 21: 10-node third order triangle 22: 12-node fourth order incomplete triangle 23: 15-node fourth order triangle 24: 15-node fifth order incomplete triangle 25: 21-node fifth order complete triangle 26: 4-node third order edge 27: 5-node fourth order edge 28: 6-node fifth order edge 29: 20-node third order tetrahedron 30: 35-node fourth order tetrahedron 31: 56-node fifth order tetrahedron -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ // The boost spirit is a work on the way it does not compile so I kept the // current code. The current code does not handle files generated on Windows // <CRLF> // #include <boost/config/warning_disable.hpp> // #include <boost/spirit/include/qi.hpp> // #include <boost/spirit/include/phoenix_core.hpp> // #include <boost/spirit/include/phoenix_fusion.hpp> // #include <boost/spirit/include/phoenix_object.hpp> // #include <boost/spirit/include/phoenix_container.hpp> // #include <boost/spirit/include/phoenix_operator.hpp> // #include <boost/spirit/include/phoenix_bind.hpp> // #include <boost/spirit/include/phoenix_stl.hpp> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* Methods Implentations */ /* -------------------------------------------------------------------------- */ MeshIOMSH::MeshIOMSH() { canReadSurface = true; canReadExtendedData = true; _msh_nodes_per_elem[_msh_not_defined] = 0; _msh_nodes_per_elem[_msh_segment_2] = 2; _msh_nodes_per_elem[_msh_triangle_3] = 3; _msh_nodes_per_elem[_msh_quadrangle_4] = 4; _msh_nodes_per_elem[_msh_tetrahedron_4] = 4; _msh_nodes_per_elem[_msh_hexahedron_8] = 8; _msh_nodes_per_elem[_msh_prism_1] = 6; _msh_nodes_per_elem[_msh_pyramid_1] = 1; _msh_nodes_per_elem[_msh_segment_3] = 3; _msh_nodes_per_elem[_msh_triangle_6] = 6; _msh_nodes_per_elem[_msh_quadrangle_9] = 9; _msh_nodes_per_elem[_msh_tetrahedron_10] = 10; _msh_nodes_per_elem[_msh_hexahedron_27] = 27; _msh_nodes_per_elem[_msh_hexahedron_20] = 20; _msh_nodes_per_elem[_msh_prism_18] = 18; _msh_nodes_per_elem[_msh_prism_15] = 15; _msh_nodes_per_elem[_msh_pyramid_14] = 14; _msh_nodes_per_elem[_msh_point] = 1; _msh_nodes_per_elem[_msh_quadrangle_8] = 8; _msh_to_akantu_element_types[_msh_not_defined] = _not_defined; _msh_to_akantu_element_types[_msh_segment_2] = _segment_2; _msh_to_akantu_element_types[_msh_triangle_3] = _triangle_3; _msh_to_akantu_element_types[_msh_quadrangle_4] = _quadrangle_4; _msh_to_akantu_element_types[_msh_tetrahedron_4] = _tetrahedron_4; _msh_to_akantu_element_types[_msh_hexahedron_8] = _hexahedron_8; _msh_to_akantu_element_types[_msh_prism_1] = _pentahedron_6; _msh_to_akantu_element_types[_msh_pyramid_1] = _not_defined; _msh_to_akantu_element_types[_msh_segment_3] = _segment_3; _msh_to_akantu_element_types[_msh_triangle_6] = _triangle_6; _msh_to_akantu_element_types[_msh_quadrangle_9] = _not_defined; _msh_to_akantu_element_types[_msh_tetrahedron_10] = _tetrahedron_10; _msh_to_akantu_element_types[_msh_hexahedron_27] = _not_defined; _msh_to_akantu_element_types[_msh_hexahedron_20] = _hexahedron_20; _msh_to_akantu_element_types[_msh_prism_18] = _not_defined; _msh_to_akantu_element_types[_msh_prism_15] = _pentahedron_15; _msh_to_akantu_element_types[_msh_pyramid_14] = _not_defined; _msh_to_akantu_element_types[_msh_point] = _point_1; _msh_to_akantu_element_types[_msh_quadrangle_8] = _quadrangle_8; _akantu_to_msh_element_types[_not_defined] = _msh_not_defined; _akantu_to_msh_element_types[_segment_2] = _msh_segment_2; _akantu_to_msh_element_types[_segment_3] = _msh_segment_3; _akantu_to_msh_element_types[_triangle_3] = _msh_triangle_3; _akantu_to_msh_element_types[_triangle_6] = _msh_triangle_6; _akantu_to_msh_element_types[_tetrahedron_4] = _msh_tetrahedron_4; _akantu_to_msh_element_types[_tetrahedron_10] = _msh_tetrahedron_10; _akantu_to_msh_element_types[_quadrangle_4] = _msh_quadrangle_4; _akantu_to_msh_element_types[_quadrangle_8] = _msh_quadrangle_8; _akantu_to_msh_element_types[_hexahedron_8] = _msh_hexahedron_8; _akantu_to_msh_element_types[_hexahedron_20] = _msh_hexahedron_20; _akantu_to_msh_element_types[_pentahedron_6] = _msh_prism_1; _akantu_to_msh_element_types[_pentahedron_15] = _msh_prism_15; _akantu_to_msh_element_types[_point_1] = _msh_point; #if defined(AKANTU_STRUCTURAL_MECHANICS) _akantu_to_msh_element_types[_bernoulli_beam_2] = _msh_segment_2; _akantu_to_msh_element_types[_bernoulli_beam_3] = _msh_segment_2; _akantu_to_msh_element_types[_discrete_kirchhoff_triangle_18] = _msh_triangle_3; #endif std::map<ElementType, MSHElementType>::iterator it; for (it = _akantu_to_msh_element_types.begin(); it != _akantu_to_msh_element_types.end(); ++it) { UInt nb_nodes = _msh_nodes_per_elem[it->second]; std::vector<UInt> tmp(nb_nodes); for (UInt i = 0; i < nb_nodes; ++i) { tmp[i] = i; } switch (it->first) { case _tetrahedron_10: tmp[8] = 9; tmp[9] = 8; break; case _pentahedron_6: tmp[0] = 2; tmp[1] = 0; tmp[2] = 1; tmp[3] = 5; tmp[4] = 3; tmp[5] = 4; break; case _pentahedron_15: tmp[0] = 2; tmp[1] = 0; tmp[2] = 1; tmp[3] = 5; tmp[4] = 3; tmp[5] = 4; tmp[6] = 8; tmp[8] = 11; tmp[9] = 6; tmp[10] = 9; tmp[11] = 10; tmp[12] = 14; tmp[14] = 12; break; case _hexahedron_20: tmp[9] = 11; tmp[10] = 12; tmp[11] = 9; tmp[12] = 13; tmp[13] = 10; tmp[17] = 19; tmp[18] = 17; tmp[19] = 18; break; default: // nothing to change break; } _read_order[it->first] = tmp; } } /* -------------------------------------------------------------------------- */ MeshIOMSH::~MeshIOMSH() = default; /* -------------------------------------------------------------------------- */ /* Spirit stuff */ /* -------------------------------------------------------------------------- */ // namespace _parser { // namespace spirit = ::boost::spirit; // namespace qi = ::boost::spirit::qi; // namespace ascii = ::boost::spirit::ascii; // namespace lbs = ::boost::spirit::qi::labels; // namespace phx = ::boost::phoenix; // /* ------------------------------------------------------------------------ // */ // /* Lazy functors */ // /* ------------------------------------------------------------------------ // */ // struct _Element { // int index; // std::vector<int> tags; // std::vector<int> connectivity; // ElementType type; // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_get_nb_nodes_ { // template <class elem_type> struct result { typedef int type; }; // template <class elem_type> bool operator()(elem_type et) { // return MeshIOMSH::_msh_nodes_per_elem[et]; // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_element_ { // template <class id_t, class tags_t, class elem_type, class conn_t> // struct result { // typedef _Element type; // }; // template <class id_t, class tags_t, class elem_type, class conn_t> // _Element operator()(id_t id, const elem_type & et, const tags_t & t, // const conn_t & c) { // _Element tmp_el; // tmp_el.index = id; // tmp_el.tags = t; // tmp_el.connectivity = c; // tmp_el.type = et; // return tmp_el; // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_check_value_ { // template <class T> struct result { typedef void type; }; // template <class T> void operator()(T v1, T v2) { // if (v1 != v2) { // AKANTU_EXCEPTION("The msh parser expected a " // << v2 << " in the header bug got a " << v1); // } // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_node_read_ { // template <class Mesh, class ID, class V, class size, class Map> // struct result { // typedef bool type; // }; // template <class Mesh, class ID, class V, class size, class Map> // bool operator()(Mesh & mesh, const ID & id, const V & pos, size max, // Map & nodes_mapping) const { // Vector<Real> tmp_pos(mesh.getSpatialDimension()); // UInt i = 0; // for (typename V::const_iterator it = pos.begin(); // it != pos.end() || i < mesh.getSpatialDimension(); ++it) // tmp_pos[i++] = *it; // nodes_mapping[id] = mesh.getNbNodes(); // mesh.getNodes().push_back(tmp_pos); // return (mesh.getNbNodes() < UInt(max)); // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_element_read_ { // template <class Mesh, class EL, class size, class NodeMap, class ElemMap> // struct result { // typedef bool type; // }; // template <class Mesh, class EL, class size, class NodeMap, class ElemMap> // bool operator()(Mesh & mesh, const EL & element, size max, // const NodeMap & nodes_mapping, // ElemMap & elements_mapping) const { // Vector<UInt> tmp_conn(Mesh::getNbNodesPerElement(element.type)); // AKANTU_DEBUG_ASSERT(element.connectivity.size() == tmp_conn.size(), // "The element " // << element.index // << "in the MSH file has too many nodes."); // mesh.addConnectivityType(element.type); // Array<UInt> & connectivity = mesh.getConnectivity(element.type); // UInt i = 0; // for (std::vector<int>::const_iterator it = // element.connectivity.begin(); // it != element.connectivity.end(); ++it) { // typename NodeMap::const_iterator nit = nodes_mapping.find(*it); // AKANTU_DEBUG_ASSERT(nit != nodes_mapping.end(), // "There is an unknown node in the connectivity."); // tmp_conn[i++] = nit->second; // } // ::akantu::Element el(element.type, connectivity.size()); // elements_mapping[element.index] = el; // connectivity.push_back(tmp_conn); // for (UInt i = 0; i < element.tags.size(); ++i) { // std::stringstream tag_sstr; // tag_sstr << "tag_" << i; // Array<UInt> * data = // mesh.template getDataPointer<UInt>(tag_sstr.str(), element.type, // _not_ghost); // data->push_back(element.tags[i]); // } // return (mesh.getNbElement() < UInt(max)); // } // }; // /* ------------------------------------------------------------------------ // */ // template <class Iterator, typename Skipper = ascii::space_type> // struct MshMeshGrammar : qi::grammar<Iterator, void(), Skipper> { // public: // MshMeshGrammar(Mesh & mesh) // : MshMeshGrammar::base_type(start, "msh_mesh_reader"), mesh(mesh) { // phx::function<lazy_element_> lazy_element; // phx::function<lazy_get_nb_nodes_> lazy_get_nb_nodes; // phx::function<lazy_check_value_> lazy_check_value; // phx::function<lazy_node_read_> lazy_node_read; // phx::function<lazy_element_read_> lazy_element_read; // clang-format off // start // = *( known_section | unknown_section // ) // ; // known_section // = qi::char_("$") // >> sections [ lbs::_a = lbs::_1 ] // >> qi::lazy(*lbs::_a) // >> qi::lit("$End") // //>> qi::lit(phx::ref(lbs::_a)) // ; // unknown_section // = qi::char_("$") // >> qi::char_("") [ lbs::_a = lbs::_1 ] // >> ignore_section // >> qi::lit("$End") // >> qi::lit(phx::val(lbs::_a)) // ; // mesh_format // version followed by 0 or 1 for ascii or binary // = version >> ( // ( qi::char_("0") // >> qi::int_ [ lazy_check_value(lbs::_1, 8) ] // ) // | ( qi::char_("1") // >> qi::int_ [ lazy_check_value(lbs::_1, 8) ] // >> qi::dword [ lazy_check_value(lbs::_1, 1) ] // ) // ) // ; // nodes // = nodes_ // ; // nodes_ // = qi::int_ [ lbs::_a = lbs::_1 ] // > *( // ( qi::int_ >> position ) [ lazy_node_read(phx::ref(mesh), // lbs::_1, // phx::cref(lbs::_2), // lbs::_a, // phx::ref(this->msh_nodes_to_akantu)) ] // ) // ; // element // = elements_ // ; // elements_ // = qi::int_ [ lbs::_a = lbs::_1 ] // > qi::repeat(phx::ref(lbs::_a))[ element [ lazy_element_read(phx::ref(mesh), // lbs::_1, // phx::cref(lbs::_a), // phx::cref(this->msh_nodes_to_akantu), // phx::ref(this->msh_elemt_to_akantu)) ]] // ; // ignore_section // = *(qi::char_ - qi::char_('$')) // ; // interpolation_scheme = ignore_section; // element_data = ignore_section; // node_data = ignore_section; // version // = qi::int_ [ phx::push_back(lbs::_val, lbs::_1) ] // >> *( qi::char_(".") >> qi::int_ [ phx::push_back(lbs::_val, lbs::_1) ] ) // ; // position // = real [ phx::push_back(lbs::_val, lbs::_1) ] // > real [ phx::push_back(lbs::_val, lbs::_1) ] // > real [ phx::push_back(lbs::_val, lbs::_1) ] // ; // tags // = qi::int_ [ lbs::_a = lbs::_1 ] // > qi::repeat(phx::val(lbs::_a))[ qi::int_ [ phx::push_back(lbs::_val, // lbs::_1) ] ] // ; // element // = ( qi::int_ [ lbs::_a = lbs::_1 ] // > msh_element_type [ lbs::_b = lazy_get_nb_nodes(lbs::_1) ] // > tags [ lbs::_c = lbs::_1 ] // > connectivity(lbs::_a) [ lbs::_d = lbs::_1 ] // ) [ lbs::_val = lazy_element(lbs::_a, // phx::cref(lbs::_b), // phx::cref(lbs::_c), // phx::cref(lbs::_d)) ] // ; // connectivity // = qi::repeat(lbs::_r1)[ qi::int_ [ phx::push_back(lbs::_val, // lbs::_1) ] ] // ; // sections.add // ("MeshFormat", &mesh_format) // ("Nodes", &nodes) // ("Elements", &elements) // ("PhysicalNames", &physical_names) // ("InterpolationScheme", &interpolation_scheme) // ("ElementData", &element_data) // ("NodeData", &node_data); // msh_element_type.add // ("0" , _not_defined ) // ("1" , _segment_2 ) // ("2" , _triangle_3 ) // ("3" , _quadrangle_4 ) // ("4" , _tetrahedron_4 ) // ("5" , _hexahedron_8 ) // ("6" , _pentahedron_6 ) // ("7" , _not_defined ) // ("8" , _segment_3 ) // ("9" , _triangle_6 ) // ("10", _not_defined ) // ("11", _tetrahedron_10) // ("12", _not_defined ) // ("13", _not_defined ) // ("14", _hexahedron_20 ) // ("15", _pentahedron_15) // ("16", _not_defined ) // ("17", _point_1 ) // ("18", _quadrangle_8 ); // mesh_format .name("MeshFormat" ); // nodes .name("Nodes" ); // elements .name("Elements" ); // physical_names .name("PhysicalNames" ); // interpolation_scheme.name("InterpolationScheme"); // element_data .name("ElementData" ); // node_data .name("NodeData" ); // clang-format on // } // /* ---------------------------------------------------------------------- // */ // /* Rules */ // /* ---------------------------------------------------------------------- // */ // private: // qi::symbols<char, ElementType> msh_element_type; // qi::symbols<char, qi::rule<Iterator, void(), Skipper> *> sections; // qi::rule<Iterator, void(), Skipper> start; // qi::rule<Iterator, void(), Skipper, qi::locals<std::string> > // unknown_section; // qi::rule<Iterator, void(), Skipper, qi::locals<qi::rule<Iterator, // Skipper> *> > known_section; // qi::rule<Iterator, void(), Skipper> mesh_format, nodes, elements, // physical_names, ignore_section, // interpolation_scheme, element_data, node_data, any_line; // qi::rule<Iterator, void(), Skipper, qi::locals<int> > nodes_; // qi::rule<Iterator, void(), Skipper, qi::locals< int, int, vector<int>, // vector<int> > > elements_; // qi::rule<Iterator, std::vector<int>(), Skipper> version; // qi::rule<Iterator, _Element(), Skipper, qi::locals<ElementType> > // element; // qi::rule<Iterator, std::vector<int>(), Skipper, qi::locals<int> > tags; // qi::rule<Iterator, std::vector<int>(int), Skipper> connectivity; // qi::rule<Iterator, std::vector<Real>(), Skipper> position; // qi::real_parser<Real, qi::real_policies<Real> > real; // /* ---------------------------------------------------------------------- // */ // /* Members */ // /* ---------------------------------------------------------------------- // */ // private: // /// reference to the mesh to read // Mesh & mesh; // /// correspondance between the numbering of nodes in the abaqus file and // in // /// the akantu mesh // std::map<UInt, UInt> msh_nodes_to_akantu; // /// correspondance between the element number in the abaqus file and the // /// Element in the akantu mesh // std::map<UInt, Element> msh_elemt_to_akantu; // }; // } // /* -------------------------------------------------------------------------- // */ // void MeshIOAbaqus::read(const std::string& filename, Mesh& mesh) { // namespace qi = boost::spirit::qi; // namespace ascii = boost::spirit::ascii; // std::ifstream infile; // infile.open(filename.c_str()); // if(!infile.good()) { // AKANTU_ERROR("Cannot open file " << filename); // } // std::string storage; // We will read the contents here. // infile.unsetf(std::ios::skipws); // No white space skipping! // std::copy(std::istream_iterator<char>(infile), // std::istream_iterator<char>(), // std::back_inserter(storage)); // typedef std::string::const_iterator iterator_t; // typedef ascii::space_type skipper; // typedef _parser::MshMeshGrammar<iterator_t, skipper> grammar; // grammar g(mesh); // skipper ws; // iterator_t iter = storage.begin(); // iterator_t end = storage.end(); // qi::phrase_parse(iter, end, g, ws); // this->setNbGlobalNodes(mesh, mesh.getNodes().size()); // MeshUtils::fillElementToSubElementsData(mesh); // } static void my_getline(std::ifstream & infile, std::string & str) { std::string tmp_str; std::getline(infile, tmp_str); str = trim(tmp_str); } /* -------------------------------------------------------------------------- */ void MeshIOMSH::read(const std::string & filename, Mesh & mesh) { MeshAccessor mesh_accessor(mesh); std::ifstream infile; infile.open(filename.c_str()); std::string line; UInt first_node_number = std::numeric_limits<UInt>::max(), last_node_number = 0, file_format = 1, current_line = 0; bool has_physical_names = false; if (!infile.good()) { AKANTU_EXCEPTION("Cannot open file " << filename); } while (infile.good()) { my_getline(infile, line); current_line++; /// read the header if (line == "$MeshFormat") { my_getline(infile, line); /// the format line std::stringstream sstr(line); std::string version; sstr >> version; Int format; sstr >> format; if (format != 0) AKANTU_ERROR("This reader can only read ASCII files."); my_getline(infile, line); /// the end of block line current_line += 2; file_format = 2; } /// read the physical names if (line == "$PhysicalNames") { has_physical_names = true; my_getline(infile, line); /// the format line std::stringstream sstr(line); UInt num_of_phys_names; sstr >> num_of_phys_names; for (UInt k(0); k < num_of_phys_names; k++) { my_getline(infile, line); std::stringstream sstr_phys_name(line); UInt phys_name_id; UInt phys_dim; sstr_phys_name >> phys_dim >> phys_name_id; std::size_t b = line.find('\"'); std::size_t e = line.rfind('\"'); std::string phys_name = line.substr(b + 1, e - b - 1); phys_name_map[phys_name_id] = phys_name; } } /// read all nodes if (line == "$Nodes" || line == "$NOD") { UInt nb_nodes; my_getline(infile, line); std::stringstream sstr(line); sstr >> nb_nodes; current_line++; Array<Real> & nodes = mesh_accessor.getNodes(); nodes.resize(nb_nodes); mesh_accessor.setNbGlobalNodes(nb_nodes); UInt index; Real coord[3]; UInt spatial_dimension = nodes.getNbComponent(); /// for each node, read the coordinates for (UInt i = 0; i < nb_nodes; ++i) { UInt offset = i * spatial_dimension; my_getline(infile, line); std::stringstream sstr_node(line); sstr_node >> index >> coord[0] >> coord[1] >> coord[2]; current_line++; first_node_number = std::min(first_node_number, index); last_node_number = std::max(last_node_number, index); /// read the coordinates for (UInt j = 0; j < spatial_dimension; ++j) nodes.storage()[offset + j] = coord[j]; } my_getline(infile, line); /// the end of block line } /// read all elements if (line == "$Elements" || line == "$ELM") { UInt nb_elements; std::vector<UInt> read_order; my_getline(infile, line); std::stringstream sstr(line); sstr >> nb_elements; current_line++; Int index; UInt msh_type; ElementType akantu_type, akantu_type_old = _not_defined; Array<UInt> * connectivity = nullptr; UInt node_per_element = 0; for (UInt i = 0; i < nb_elements; ++i) { my_getline(infile, line); std::stringstream sstr_elem(line); current_line++; sstr_elem >> index; sstr_elem >> msh_type; /// get the connectivity vector depending on the element type akantu_type = this->_msh_to_akantu_element_types[(MSHElementType)msh_type]; if (akantu_type == _not_defined) { AKANTU_DEBUG_WARNING("Unsuported element kind " << msh_type << " at line " << current_line); continue; } if (akantu_type != akantu_type_old) { connectivity = &mesh_accessor.getConnectivity(akantu_type); // connectivity->resize(0); node_per_element = connectivity->getNbComponent(); akantu_type_old = akantu_type; read_order = this->_read_order[akantu_type]; } /// read tags informations if (file_format == 2) { UInt nb_tags; sstr_elem >> nb_tags; for (UInt j = 0; j < nb_tags; ++j) { Int tag; sstr_elem >> tag; std::stringstream sstr_tag_name; sstr_tag_name << "tag_" << j; Array<UInt> & data = mesh.getDataPointer<UInt>( sstr_tag_name.str(), akantu_type, _not_ghost); data.push_back(tag); } } else if (file_format == 1) { Int tag; sstr_elem >> tag; // reg-phys std::string tag_name = "tag_0"; Array<UInt> * data = &mesh.getDataPointer<UInt>(tag_name, akantu_type, _not_ghost); data->push_back(tag); sstr_elem >> tag; // reg-elem tag_name = "tag_1"; data = &mesh.getDataPointer<UInt>(tag_name, akantu_type, _not_ghost); data->push_back(tag); sstr_elem >> tag; // number-of-nodes } Vector<UInt> local_connect(node_per_element); for (UInt j = 0; j < node_per_element; ++j) { UInt node_index; sstr_elem >> node_index; AKANTU_DEBUG_ASSERT(node_index <= last_node_number, "Node number not in range : line " << current_line); node_index -= first_node_number; local_connect(read_order[j]) = node_index; } connectivity->push_back(local_connect); } my_getline(infile, line); /// the end of block line } if ((line[0] == '$') && (line.find("End") == std::string::npos)) { AKANTU_DEBUG_WARNING("Unsuported block_kind " << line << " at line " << current_line); } } // mesh.updateTypesOffsets(_not_ghost); infile.close(); this->constructPhysicalNames("tag_0", mesh); if (has_physical_names) mesh.createGroupsFromMeshData<std::string>("physical_names"); MeshUtils::fillElementToSubElementsData(mesh); } /* -------------------------------------------------------------------------- */ void MeshIOMSH::write(const std::string & filename, const Mesh & mesh) { std::ofstream outfile; const Array<Real> & nodes = mesh.getNodes(); outfile.open(filename.c_str()); outfile << "$MeshFormat" << std::endl; outfile << "2.1 0 8" << std::endl; outfile << "$EndMeshFormat" << std::endl; outfile << std::setprecision(std::numeric_limits<Real>::digits10); outfile << "$Nodes" << std::endl; outfile << nodes.size() << std::endl; outfile << std::uppercase; for (UInt i = 0; i < nodes.size(); ++i) { Int offset = i * nodes.getNbComponent(); outfile << i + 1; for (UInt j = 0; j < nodes.getNbComponent(); ++j) { outfile << " " << nodes.storage()[offset + j]; } for (UInt p = nodes.getNbComponent(); p < 3; ++p) outfile << " " << 0.; outfile << std::endl; ; } outfile << std::nouppercase; outfile << "$EndNodes" << std::endl; ; outfile << "$Elements" << std::endl; ; Int nb_elements = 0; for (auto && type : mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { const Array<UInt> & connectivity = mesh.getConnectivity(type, _not_ghost); nb_elements += connectivity.size(); } outfile << nb_elements << std::endl; UInt element_idx = 1; for (auto && type : mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { const auto & connectivity = mesh.getConnectivity(type, _not_ghost); UInt * tag[2] = {nullptr, nullptr}; if (mesh.hasData<UInt>("tag_0", type, _not_ghost)) { const auto & data_tag_0 = mesh.getData<UInt>("tag_0", type, _not_ghost); tag[0] = data_tag_0.storage(); } if (mesh.hasData<UInt>("tag_1", type, _not_ghost)) { const auto & data_tag_1 = mesh.getData<UInt>("tag_1", type, _not_ghost); tag[1] = data_tag_1.storage(); } for (UInt i = 0; i < connectivity.size(); ++i) { UInt offset = i * connectivity.getNbComponent(); outfile << element_idx << " " << _akantu_to_msh_element_types[type] << " 2"; /// \todo write the real data in the file for (UInt t = 0; t < 2; ++t) if (tag[t]) outfile << " " << tag[t][i]; else outfile << " 0"; for (UInt j = 0; j < connectivity.getNbComponent(); ++j) { outfile << " " << connectivity.storage()[offset + j] + 1; } outfile << std::endl; element_idx++; } } outfile << "$EndElements" << std::endl; ; outfile.close(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/io/mesh_io/mesh_io_msh.hh b/src/io/mesh_io/mesh_io_msh.hh index 70c52f4c4..568f5cca6 100644 --- a/src/io/mesh_io/mesh_io_msh.hh +++ b/src/io/mesh_io/mesh_io_msh.hh @@ -1,110 +1,109 @@ /** * @file mesh_io_msh.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Mon Dec 07 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Read/Write for MSH files * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_IO_MSH_HH__ #define __AKANTU_MESH_IO_MSH_HH__ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class MeshIOMSH : public MeshIO { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshIOMSH(); ~MeshIOMSH() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// read a mesh from the file void read(const std::string & filename, Mesh & mesh) override; /// write a mesh to a file void write(const std::string & filename, const Mesh & mesh) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// MSH element types enum MSHElementType { _msh_not_defined = 0, _msh_segment_2 = 1, // 2-node line. _msh_triangle_3 = 2, // 3-node triangle. _msh_quadrangle_4 = 3, // 4-node quadrangle. _msh_tetrahedron_4 = 4, // 4-node tetrahedron. _msh_hexahedron_8 = 5, // 8-node hexahedron. _msh_prism_1 = 6, // 6-node prism. _msh_pyramid_1 = 7, // 5-node pyramid. _msh_segment_3 = 8, // 3-node second order line _msh_triangle_6 = 9, // 6-node second order triangle _msh_quadrangle_9 = 10, // 9-node second order quadrangle _msh_tetrahedron_10 = 11, // 10-node second order tetrahedron _msh_hexahedron_27 = 12, // 27-node second order hexahedron _msh_prism_18 = 13, // 18-node second order prism _msh_pyramid_14 = 14, // 14-node second order pyramid _msh_point = 15, // 1-node point. _msh_quadrangle_8 = 16, // 8-node second order quadrangle _msh_hexahedron_20 = 17, // 20-node second order hexahedron _msh_prism_15 = 18 // 15-node second order prism }; #define MAX_NUMBER_OF_NODE_PER_ELEMENT 10 // tetrahedron of second order /// order in witch element as to be read std::map<ElementType, std::vector<UInt>> _read_order; /// number of nodes per msh element std::map<MSHElementType, UInt> _msh_nodes_per_elem; /// correspondence between msh element types and akantu element types std::map<MSHElementType, ElementType> _msh_to_akantu_element_types; /// correspondence between akantu element types and msh element types std::map<ElementType, MSHElementType> _akantu_to_msh_element_types; }; } // akantu #endif /* __AKANTU_MESH_IO_MSH_HH__ */ diff --git a/src/io/mesh_io/mesh_io_msh_struct.cc b/src/io/mesh_io/mesh_io_msh_struct.cc index 96f3fbec8..55300ef69 100644 --- a/src/io/mesh_io/mesh_io_msh_struct.cc +++ b/src/io/mesh_io/mesh_io_msh_struct.cc @@ -1,80 +1,80 @@ /** * @file mesh_io_msh_struct.cc * + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Mon Dec 07 2015 + * @date last modification: Fri Jan 26 2018 * * @brief Read/Write for MSH files generated by gmsh * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_io_msh_struct.hh" /* -------------------------------------------------------------------------- */ #include <numeric> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MeshIOMSHStruct::MeshIOMSHStruct() : MeshIOMSH() { canReadSurface = true; canReadExtendedData = true; _msh_to_akantu_element_types.clear(); _msh_to_akantu_element_types[_msh_not_defined] = _not_defined; _msh_to_akantu_element_types[_msh_segment_2] = _bernoulli_beam_2; _msh_to_akantu_element_types[_msh_triangle_3] = _discrete_kirchhoff_triangle_18; _akantu_to_msh_element_types.clear(); _akantu_to_msh_element_types[_not_defined] = _msh_not_defined; _akantu_to_msh_element_types[_bernoulli_beam_2] = _msh_segment_2; _akantu_to_msh_element_types[_bernoulli_beam_3] = _msh_segment_2; _akantu_to_msh_element_types[_discrete_kirchhoff_triangle_18] = _msh_triangle_3; for (auto & kv_pair : _akantu_to_msh_element_types) { UInt nb_nodes = _msh_nodes_per_elem[kv_pair.second]; std::vector<UInt> tmp(nb_nodes); std::iota(tmp.begin(), tmp.end(), 0); _read_order[kv_pair.first] = tmp; } } /* -------------------------------------------------------------------------- */ void MeshIOMSHStruct::read(const std::string & filename, Mesh & mesh) { if (mesh.getSpatialDimension() == 2) { _msh_to_akantu_element_types[_msh_segment_2] = _bernoulli_beam_2; } else if (mesh.getSpatialDimension() == 3) { _msh_to_akantu_element_types[_msh_segment_2] = _bernoulli_beam_3; AKANTU_DEBUG_WARNING("The MeshIOMSHStruct is reading bernoulli beam 3D be " "sure to provide the missing normals with the element " "data \"extra_normal\""); } MeshIOMSH::read(filename, mesh); } } // akantu diff --git a/src/io/mesh_io/mesh_io_msh_struct.hh b/src/io/mesh_io/mesh_io_msh_struct.hh index b83045ce5..542d65743 100644 --- a/src/io/mesh_io/mesh_io_msh_struct.hh +++ b/src/io/mesh_io/mesh_io_msh_struct.hh @@ -1,54 +1,54 @@ /** * @file mesh_io_msh_struct.hh * + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Fri Jan 26 2018 * * @brief Read/Write for MSH files * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_IO_MSH_STRUCT_HH__ #define __AKANTU_MESH_IO_MSH_STRUCT_HH__ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class MeshIOMSHStruct : public MeshIOMSH { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshIOMSHStruct(); /// read a mesh from the file void read(const std::string & filename, Mesh & mesh) override; }; } // akantu #endif /* __AKANTU_MESH_IO_MSH_STRUCT_HH__ */ diff --git a/src/io/parser/algebraic_parser.hh b/src/io/parser/algebraic_parser.hh index da97a2380..bfecaeb63 100644 --- a/src/io/parser/algebraic_parser.hh +++ b/src/io/parser/algebraic_parser.hh @@ -1,512 +1,512 @@ /** * @file algebraic_parser.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Wed Nov 11 2015 + * @date last modification: Wed Nov 08 2017 * * @brief algebraic_parser definition of the grammar * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ // Boost #include <boost/config/warning_disable.hpp> #include <boost/spirit/include/phoenix.hpp> #include <boost/spirit/include/qi.hpp> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ALGEBRAIC_PARSER_HH__ #define __AKANTU_ALGEBRAIC_PARSER_HH__ namespace spirit = boost::spirit; namespace qi = boost::spirit::qi; namespace lbs = boost::spirit::qi::labels; namespace ascii = boost::spirit::ascii; namespace phx = boost::phoenix; namespace akantu { namespace parser { struct algebraic_error_handler_ { template <typename, typename, typename> struct result { using type = void; }; template <typename Iterator> void operator()(qi::info const & what, Iterator err_pos, Iterator last) const { AKANTU_EXCEPTION( "Error! Expecting " << what // what failed? << " here: \"" << std::string(err_pos, last) // iterators to error-pos, end << "\""); } }; static Real my_min(Real a, Real b) { return std::min(a, b); } static Real my_max(Real a, Real b) { return std::max(a, b); } static Real my_pow(Real a, Real b) { return std::pow(a, b); } static Real eval_param(const ID & a, const ParserSection & section) { return section.getParameter(a, _ppsc_current_and_parent_scope); } static Real unary_func(Real (*func)(Real), Real a) { return func(a); } static Real binary_func(Real (*func)(Real, Real), Real a, Real b) { return func(a, b); } template <class Iterator, typename Skipper = spirit::unused_type> struct AlgebraicGrammar : qi::grammar<Iterator, Real(), Skipper> { AlgebraicGrammar(const ParserSection & section) : AlgebraicGrammar::base_type(start, "algebraic_grammar"), section(section) { // phx::function<lazy_pow_> lazy_pow; // phx::function<lazy_unary_func_> lazy_unary_func; // phx::function<lazy_binary_func_> lazy_binary_func; // phx::function<lazy_eval_param_> lazy_eval_param; /* clang-format off */ start = expr.alias() ; expr = term [ lbs::_val = lbs::_1 ] >> *( ('+' > term [ lbs::_val += lbs::_1 ]) | ('-' > term [ lbs::_val -= lbs::_1 ]) ) ; term = factor [ lbs::_val = lbs::_1 ] >> *( ('*' > factor [ lbs::_val *= lbs::_1 ]) | ('/' > factor [ lbs::_val /= lbs::_1 ]) ) ; factor = number [ lbs::_val = lbs::_1 ] >> *("**" > number [ lbs::_val = phx::bind(&my_pow, lbs::_val, lbs::_1) ]) ; number = real [ lbs::_val = lbs::_1 ] | ('-' > number [ lbs::_val = -lbs::_1 ]) | ('+' > number [ lbs::_val = lbs::_1 ]) | constant [ lbs::_val = lbs::_1 ] | function [ lbs::_val = lbs::_1 ] | ('(' > expr > ')') [ lbs::_val = lbs::_1 ] | variable [ lbs::_val = lbs::_1 ] ; function = (qi::no_case[unary_function] > '(' > expr > ')') [ lbs::_val = phx::bind(&unary_func, lbs::_1, lbs::_2) ] | (qi::no_case[binary_function] > '(' >> expr > ',' >> expr > ')') [ lbs::_val = phx::bind(&binary_func ,lbs::_1, lbs::_2, lbs::_3) ] ; variable = key [ lbs::_val = phx::bind(&eval_param, lbs::_1, section) ] ; key = qi::no_skip[qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9")] // coming from the InputFileGrammar ; #ifndef M_PI # define M_PI 3.14159265358979323846 #endif #ifndef M_E # define M_E 2.7182818284590452354 #endif constant.add ("pi", M_PI) ("e", M_E); unary_function.add ("abs" , &std::abs ) ("acos" , &std::acos ) ("asin" , &std::asin ) ("atan" , &std::atan ) ("ceil" , &std::ceil ) ("cos" , &std::cos ) ("cosh" , &std::cosh ) ("exp" , &std::exp ) ("floor" , &std::floor ) ("log10" , &std::log10 ) ("log" , &std::log ) ("sin" , &std::sin ) ("sinh" , &std::sinh ) ("sqrt" , &std::sqrt ) ("tan" , &std::tan ) ("tanh" , &std::tanh ) ("acosh" , &std::acosh ) ("asinh" , &std::asinh ) ("atanh" , &std::atanh ) ("exp2" , &std::exp2 ) ("expm1" , &std::expm1 ) ("log1p" , &std::log1p ) ("log2" , &std::log2 ) ("erf" , &std::erf ) ("erfc" , &std::erfc ) ("lgamma", &std::lgamma) ("tgamma", &std::tgamma) ("trunc" , &std::trunc ) ("round" , &std::round ) // ("crbt" , &std::crbt ) ; binary_function.add ("pow" , &std::pow ) ("min" , &parser::my_min) ("max" , &parser::my_max) ("atan2", &std::atan2 ) ("fmod" , &std::fmod ) ("hypot", &std::hypot ) ; #if !defined(AKANTU_NDEBUG) phx::function<algebraic_error_handler_> const error_handler = algebraic_error_handler_(); qi::on_error<qi::fail>(start, error_handler(lbs::_4, lbs::_3, lbs::_2)); #endif expr .name("expression"); term .name("term"); factor .name("factor"); number .name("numerical-value"); variable.name("variable"); function.name("function"); constant.name("constants-list"); unary_function.name("unary-functions-list"); binary_function.name("binary-functions-list"); #if !defined AKANTU_NDEBUG if(AKANTU_DEBUG_TEST(dblDebug)) { qi::debug(expr); qi::debug(term); qi::debug(factor); qi::debug(number); qi::debug(variable); qi::debug(function); } #endif } /* clang-format on */ private: qi::rule<Iterator, Real(), Skipper> start; qi::rule<Iterator, Real(), Skipper> expr; qi::rule<Iterator, Real(), Skipper> term; qi::rule<Iterator, Real(), Skipper> factor; qi::rule<Iterator, Real(), Skipper> number; qi::rule<Iterator, Real(), Skipper> variable; qi::rule<Iterator, Real(), Skipper> function; qi::rule<Iterator, std::string(), Skipper> key; qi::real_parser<Real, qi::real_policies<Real>> real; qi::symbols<char, Real> constant; qi::symbols<char, Real (*)(Real)> unary_function; qi::symbols<char, Real (*)(Real, Real)> binary_function; const ParserSection & section; }; /* ---------------------------------------------------------------------- */ /* Vector Parser */ /* ---------------------------------------------------------------------- */ struct parsable_vector { operator Vector<Real>() { Vector<Real> tmp(_cells.size()); auto it = _cells.begin(); for (UInt i = 0; it != _cells.end(); ++it, ++i) tmp(i) = *it; return tmp; } std::vector<Real> _cells; }; inline std::ostream & operator<<(std::ostream & stream, const parsable_vector & pv) { stream << "pv["; auto it = pv._cells.begin(); if (it != pv._cells.end()) { stream << *it; for (++it; it != pv._cells.end(); ++it) stream << ", " << *it; } stream << "]"; return stream; } struct parsable_matrix { operator Matrix<Real>() { size_t cols = 0; auto it_rows = _cells.begin(); for (; it_rows != _cells.end(); ++it_rows) cols = std::max(cols, it_rows->_cells.size()); Matrix<Real> tmp(_cells.size(), _cells[0]._cells.size(), 0.); it_rows = _cells.begin(); for (UInt i = 0; it_rows != _cells.end(); ++it_rows, ++i) { auto it_cols = it_rows->_cells.begin(); for (UInt j = 0; it_cols != it_rows->_cells.end(); ++it_cols, ++j) { tmp(i, j) = *it_cols; } } return tmp; } std::vector<parsable_vector> _cells; }; inline std::ostream & operator<<(std::ostream & stream, const parsable_matrix & pm) { stream << "pm["; auto it = pm._cells.begin(); if (it != pm._cells.end()) { stream << *it; for (++it; it != pm._cells.end(); ++it) stream << ", " << *it; } stream << "]"; return stream; } /* ---------------------------------------------------------------------- */ template <typename T1, typename T2> static void cont_add(T1 & cont, T2 & value) { cont._cells.push_back(value); } /* ---------------------------------------------------------------------- */ template <class Iterator, typename Skipper = spirit::unused_type> struct VectorGrammar : qi::grammar<Iterator, parsable_vector(), Skipper> { VectorGrammar(const ParserSection & section) : VectorGrammar::base_type(start, "vector_algebraic_grammar"), number(section) { start = '[' > vector > ']'; vector = (number[phx::bind(&cont_add<parsable_vector, Real>, lbs::_a, lbs::_1)] >> *(',' >> number[phx::bind(&cont_add<parsable_vector, Real>, lbs::_a, lbs::_1)]))[lbs::_val = lbs::_a]; #if !defined(AKANTU_NDEBUG) && defined(AKANTU_CORE_CXX_11) phx::function<algebraic_error_handler_> const error_handler = algebraic_error_handler_(); qi::on_error<qi::fail>(start, error_handler(lbs::_4, lbs::_3, lbs::_2)); #endif start.name("start"); vector.name("vector"); number.name("value"); #if !defined AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDebug)) { qi::debug(start); qi::debug(vector); } #endif } private: qi::rule<Iterator, parsable_vector(), Skipper> start; qi::rule<Iterator, parsable_vector(), qi::locals<parsable_vector>, Skipper> vector; qi::rule<Iterator, Real(), Skipper> value; AlgebraicGrammar<Iterator, Skipper> number; }; /* ---------------------------------------------------------------------- */ static inline bool vector_eval(const ID & a, const ParserSection & section, parsable_vector & result) { std::string value = section.getParameter(a, _ppsc_current_and_parent_scope); std::string::const_iterator b = value.begin(); std::string::const_iterator e = value.end(); parser::VectorGrammar<std::string::const_iterator, qi::space_type> grammar( section); return qi::phrase_parse(b, e, grammar, qi::space, result); } /* ---------------------------------------------------------------------- */ template <class Iterator, typename Skipper = spirit::unused_type> struct MatrixGrammar : qi::grammar<Iterator, parsable_matrix(), Skipper> { MatrixGrammar(const ParserSection & section) : MatrixGrammar::base_type(start, "matrix_algebraic_grammar"), vector(section) { start = '[' >> matrix >> ']'; matrix = (rows[phx::bind(&cont_add<parsable_matrix, parsable_vector>, lbs::_a, lbs::_1)] >> *(',' >> rows[phx::bind(&cont_add<parsable_matrix, parsable_vector>, lbs::_a, lbs::_1)]))[lbs::_val = lbs::_a]; rows = eval_vector | vector; eval_vector = (key[lbs::_pass = phx::bind(&vector_eval, lbs::_1, section, lbs::_a)])[lbs::_val = lbs::_a]; key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9") // coming from the InputFileGrammar ; #if !defined(AKANTU_NDEBUG) && defined(AKANTU_CORE_CXX_11) phx::function<algebraic_error_handler_> const error_handler = algebraic_error_handler_(); qi::on_error<qi::fail>(start, error_handler(lbs::_4, lbs::_3, lbs::_2)); #endif start.name("matrix"); matrix.name("all_rows"); rows.name("rows"); vector.name("vector"); eval_vector.name("eval_vector"); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDebug)) { qi::debug(start); qi::debug(matrix); qi::debug(rows); qi::debug(eval_vector); qi::debug(key); } #endif } private: qi::rule<Iterator, parsable_matrix(), Skipper> start; qi::rule<Iterator, parsable_matrix(), qi::locals<parsable_matrix>, Skipper> matrix; qi::rule<Iterator, parsable_vector(), Skipper> rows; qi::rule<Iterator, parsable_vector(), qi::locals<parsable_vector>, Skipper> eval_vector; qi::rule<Iterator, std::string(), Skipper> key; VectorGrammar<Iterator, Skipper> vector; }; /* ---------------------------------------------------------------------- */ /* Randon Generator */ /* ---------------------------------------------------------------------- */ struct ParsableRandomGenerator { ParsableRandomGenerator( Real base = Real(), const RandomDistributionType & type = _rdt_not_defined, const parsable_vector & parameters = parsable_vector()) : base(base), type(type), parameters(parameters) {} Real base; RandomDistributionType type; parsable_vector parameters; }; inline std::ostream & operator<<(std::ostream & stream, const ParsableRandomGenerator & prg) { stream << "prg[" << prg.base << " " << UInt(prg.type) << " " << prg.parameters << "]"; return stream; } /* ---------------------------------------------------------------------- */ template <class Iterator, typename Skipper = spirit::unused_type> struct RandomGeneratorGrammar : qi::grammar<Iterator, ParsableRandomGenerator(), Skipper> { RandomGeneratorGrammar(const ParserSection & section) : RandomGeneratorGrammar::base_type(start, "random_generator_grammar"), number(section) { start = generator.alias(); generator = qi::hold[distribution[lbs::_val = lbs::_1]] | number[lbs::_val = phx::construct<ParsableRandomGenerator>(lbs::_1)]; distribution = (number >> generator_type >> '[' >> generator_params >> ']')[lbs::_val = phx::construct<ParsableRandomGenerator>( lbs::_1, lbs::_2, lbs::_3)]; generator_params = (number[phx::bind(&cont_add<parsable_vector, Real>, lbs::_a, lbs::_1)] >> *(',' > number[phx::bind(&cont_add<parsable_vector, Real>, lbs::_a, lbs::_1)]))[lbs::_val = lbs::_a]; #define AKANTU_RANDOM_DISTRIBUTION_TYPE_ADD(r, data, elem) \ (BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, elem)), \ AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX(BOOST_PP_TUPLE_ELEM(2, 0, elem))) generator_type.add BOOST_PP_SEQ_FOR_EACH( AKANTU_RANDOM_DISTRIBUTION_TYPE_ADD, _, AKANTU_RANDOM_DISTRIBUTION_TYPES); #undef AKANTU_RANDOM_DISTRIBUTION_TYPE_ADD #if !defined(AKANTU_NDEBUG) && defined(AKANTU_CORE_CXX_11) phx::function<algebraic_error_handler_> const error_handler = algebraic_error_handler_(); qi::on_error<qi::fail>(start, error_handler(lbs::_4, lbs::_3, lbs::_2)); #endif start.name("random-generator"); generator.name("random-generator"); distribution.name("random-distribution"); generator_type.name("generator-type"); generator_params.name("generator-parameters"); number.name("number"); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDebug)) { qi::debug(generator); qi::debug(distribution); qi::debug(generator_params); } #endif } private: qi::rule<Iterator, ParsableRandomGenerator(), Skipper> start; qi::rule<Iterator, ParsableRandomGenerator(), Skipper> generator; qi::rule<Iterator, ParsableRandomGenerator(), Skipper> distribution; qi::rule<Iterator, parsable_vector(), qi::locals<parsable_vector>, Skipper> generator_params; AlgebraicGrammar<Iterator, Skipper> number; qi::symbols<char, RandomDistributionType> generator_type; }; } } #endif /* __AKANTU_ALGEBRAIC_PARSER_HH__ */ diff --git a/src/io/parser/cppargparse/cppargparse.cc b/src/io/parser/cppargparse/cppargparse.cc index 5c3280299..55ab84290 100644 --- a/src/io/parser/cppargparse/cppargparse.cc +++ b/src/io/parser/cppargparse/cppargparse.cc @@ -1,523 +1,523 @@ /** * @file cppargparse.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Apr 03 2014 - * @date last modification: Wed Nov 11 2015 + * @date last modification: Wed Nov 08 2017 * * @brief implementation of the ArgumentParser * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "cppargparse.hh" #include <cstdlib> #include <cstring> #include <libgen.h> #include <algorithm> #include <iomanip> #include <iostream> #include <queue> #include <sstream> #include <string> #include <exception> #include <stdexcept> #include <string.h> namespace cppargparse { /* -------------------------------------------------------------------------- */ static inline std::string to_upper(const std::string & str) { std::string lstr = str; std::transform(lstr.begin(), lstr.end(), lstr.begin(), (int (*)(int))std::toupper); return lstr; } /* -------------------------------------------------------------------------- */ /* ArgumentParser */ /* -------------------------------------------------------------------------- */ ArgumentParser::ArgumentParser() { this->addArgument("-h;--help", "show this help message and exit", 0, _boolean, false, true); } /* -------------------------------------------------------------------------- */ ArgumentParser::~ArgumentParser() { for (auto it = arguments.begin(); it != arguments.end(); ++it) { delete it->second; } } /* -------------------------------------------------------------------------- */ void ArgumentParser::setParallelContext(int prank, int psize) { this->prank = prank; this->psize = psize; } /* -------------------------------------------------------------------------- */ void ArgumentParser::_exit(const std::string & msg, int status) { if (prank == 0) { if (msg != "") { std::cerr << msg << std::endl; std::cerr << std::endl; } this->print_help(std::cerr); } if (external_exit) (*external_exit)(status); else { exit(status); } } /* -------------------------------------------------------------------------- */ const ArgumentParser::Argument & ArgumentParser:: operator[](const std::string & name) const { auto it = success_parsed.find(name); if (it != success_parsed.end()) { return *(it->second); } else { throw std::range_error("No argument named \'" + name + "\' was found in the parsed argument," + " make sur to specify it \'required\'" + " or to give it a default value"); } } /* -------------------------------------------------------------------------- */ bool ArgumentParser::has(const std::string & name) const { return (success_parsed.find(name) != success_parsed.end()); } /* -------------------------------------------------------------------------- */ void ArgumentParser::addArgument(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type) { _addArgument(name_or_flag, help, nargs, type); } /* -------------------------------------------------------------------------- */ ArgumentParser::_Argument & ArgumentParser::_addArgument(const std::string & name, const std::string & help, int nargs, ArgumentType type) { _Argument * arg = nullptr; switch (type) { case _string: { arg = new ArgumentStorage<std::string>(); break; } case _float: { arg = new ArgumentStorage<double>(); break; } case _integer: { arg = new ArgumentStorage<int>(); break; } case _boolean: { arg = new ArgumentStorage<bool>(); break; } } arg->help = help; arg->nargs = nargs; arg->type = type; std::stringstream sstr(name); std::string item; std::vector<std::string> tmp_keys; while (std::getline(sstr, item, ';')) { tmp_keys.push_back(item); } int long_key = -1; int short_key = -1; bool problem = (tmp_keys.size() > 2) || (name == ""); for (auto it = tmp_keys.begin(); it != tmp_keys.end(); ++it) { if (it->find("--") == 0) { problem |= (long_key != -1); long_key = it - tmp_keys.begin(); } else if (it->find("-") == 0) { problem |= (long_key != -1); short_key = it - tmp_keys.begin(); } } problem |= ((tmp_keys.size() == 2) && (long_key == -1 || short_key == -1)); if (problem) { delete arg; throw std::invalid_argument("Synthax of name or flags is not correct. " "Possible synthax are \'-f\', \'-f;--foo\', " "\'--foo\', \'bar\'"); } if (long_key != -1) { arg->name = tmp_keys[long_key]; arg->name.erase(0, 2); } else if (short_key != -1) { arg->name = tmp_keys[short_key]; arg->name.erase(0, 1); } else { arg->name = tmp_keys[0]; pos_args.push_back(arg); arg->required = (nargs != _one_if_possible); arg->is_positional = true; } arguments[arg->name] = arg; if (!arg->is_positional) { if (short_key != -1) { std::string key = tmp_keys[short_key]; key_args[key] = arg; arg->keys.push_back(key); } if (long_key != -1) { std::string key = tmp_keys[long_key]; key_args[key] = arg; arg->keys.push_back(key); } } return *arg; } #if not HAVE_STRDUP static char * strdup(const char * str) { size_t len = strlen(str); auto * x = (char *)malloc(len + 1); /* 1 for the null terminator */ if (!x) return nullptr; /* malloc could not allocate memory */ memcpy(x, str, len + 1); /* copy the string into the new buffer */ return x; } #endif /* -------------------------------------------------------------------------- */ void ArgumentParser::parse(int & argc, char **& argv, int flags, bool parse_help) { bool stop_in_not_parsed = flags & _stop_on_not_parsed; bool remove_parsed = flags & _remove_parsed; std::vector<std::string> argvs; argvs.reserve(argc); for (int i = 0; i < argc; ++i) { argvs.emplace_back(argv[i]); } unsigned int current_position = 0; if (this->program_name == "" && argc > 0) { std::string prog = argvs[current_position]; const char * c_prog = prog.c_str(); char * c_prog_tmp = strdup(c_prog); std::string base_prog(basename(c_prog_tmp)); this->program_name = base_prog; std::free(c_prog_tmp); } std::queue<_Argument *> positional_queue; for (auto it = pos_args.begin(); it != pos_args.end(); ++it) positional_queue.push(*it); std::vector<int> argvs_to_remove; ++current_position; // consume argv[0] while (current_position < argvs.size()) { std::string arg = argvs[current_position]; ++current_position; auto key_it = key_args.find(arg); bool is_positional = false; _Argument * argument_ptr = nullptr; if (key_it == key_args.end()) { if (positional_queue.empty()) { if (stop_in_not_parsed) this->_exit("Argument " + arg + " not recognized", EXIT_FAILURE); continue; } else { argument_ptr = positional_queue.front(); is_positional = true; --current_position; } } else { argument_ptr = key_it->second; } if (remove_parsed && !is_positional && argument_ptr->name != "help") { argvs_to_remove.push_back(current_position - 1); } _Argument & argument = *argument_ptr; unsigned int min_nb_val = 0, max_nb_val = 0; switch (argument.nargs) { case _one_if_possible: max_nb_val = 1; break; // "?" case _at_least_one: min_nb_val = 1; // "+" /* FALLTHRU */ /* [[fallthrough]]; un-comment when compiler will get it*/ case _any: max_nb_val = argc - current_position; break; // "*" default: min_nb_val = max_nb_val = argument.nargs; // "N" } std::vector<std::string> values; unsigned int arg_consumed = 0; if (max_nb_val <= (argc - current_position)) { for (; arg_consumed < max_nb_val; ++arg_consumed) { std::string v = argvs[current_position]; ++current_position; bool is_key = key_args.find(v) != key_args.end(); bool is_good_type = checkType(argument.type, v); if (!is_key && is_good_type) { values.push_back(v); if (remove_parsed) argvs_to_remove.push_back(current_position - 1); } else { // unconsume not parsed argument for optional if (!is_positional || is_key) --current_position; break; } } } if (arg_consumed < min_nb_val) { if (!is_positional) { this->_exit("Not enought values for the argument " + argument.name + " where provided", EXIT_FAILURE); } else { if (stop_in_not_parsed) this->_exit("Argument " + arg + " not recognized", EXIT_FAILURE); } } else { if (is_positional) positional_queue.pop(); if (!argument.parsed) { success_parsed[argument.name] = &argument; argument.parsed = true; if ((argument.nargs == _one_if_possible || argument.nargs == 0) && arg_consumed == 0) { if (argument.has_const) argument.setToConst(); else if (argument.has_default) argument.setToDefault(); } else { argument.setValues(values); } } else { this->_exit("Argument " + argument.name + " already present in the list of argument", EXIT_FAILURE); } } } for (auto ait = arguments.begin(); ait != arguments.end(); ++ait) { _Argument & argument = *(ait->second); if (!argument.parsed) { if (argument.has_default) { argument.setToDefault(); success_parsed[argument.name] = &argument; } if (argument.required) { this->_exit("Argument " + argument.name + " required but not given!", EXIT_FAILURE); } } } // removing the parsed argument if remove_parsed is true if (argvs_to_remove.size()) { std::vector<int>::const_iterator next_to_remove = argvs_to_remove.begin(); for (int i = 0, c = 0; i < argc; ++i) { if (next_to_remove == argvs_to_remove.end() || i != *next_to_remove) { argv[c] = argv[i]; ++c; } else { if (next_to_remove != argvs_to_remove.end()) ++next_to_remove; } } argc -= argvs_to_remove.size(); } this->argc = &argc; this->argv = &argv; if (this->arguments["help"]->parsed && parse_help) { this->_exit(); } } /* -------------------------------------------------------------------------- */ bool ArgumentParser::checkType(ArgumentType type, const std::string & value) const { std::stringstream sstr(value); switch (type) { case _string: { std::string s; sstr >> s; break; } case _float: { double d; sstr >> d; break; } case _integer: { int i; sstr >> i; break; } case _boolean: { bool b; sstr >> b; break; } } return (sstr.fail() == false); } /* -------------------------------------------------------------------------- */ void ArgumentParser::printself(std::ostream & stream) const { for (auto it = success_parsed.begin(); it != success_parsed.end(); ++it) { const Argument & argument = *(it->second); argument.printself(stream); stream << std::endl; } } /* -------------------------------------------------------------------------- */ void ArgumentParser::print_usage(std::ostream & stream) const { stream << "Usage: " << this->program_name; // print shorten usage for (auto it = arguments.begin(); it != arguments.end(); ++it) { const _Argument & argument = *(it->second); if (!argument.is_positional) { if (!argument.required) stream << " ["; stream << argument.keys[0]; this->print_usage_nargs(stream, argument); if (!argument.required) stream << "]"; } } for (auto it = pos_args.begin(); it != pos_args.end(); ++it) { const _Argument & argument = **it; this->print_usage_nargs(stream, argument); } stream << std::endl; } /* -------------------------------------------------------------------------- */ void ArgumentParser::print_usage_nargs(std::ostream & stream, const _Argument & argument) const { std::string u_name = to_upper(argument.name); switch (argument.nargs) { case _one_if_possible: stream << " [" << u_name << "]"; break; case _at_least_one: stream << " " << u_name; /* FALLTHRU */ /* [[fallthrough]]; un-comment when compiler will get it */ case _any: stream << " [" << u_name << " ...]"; break; default: for (int i = 0; i < argument.nargs; ++i) { stream << " " << u_name; } } } void ArgumentParser::print_help(std::ostream & stream) const { this->print_usage(stream); if (!pos_args.empty()) { stream << std::endl; stream << "positional arguments:" << std::endl; for (auto it = pos_args.begin(); it != pos_args.end(); ++it) { const _Argument & argument = **it; this->print_help_argument(stream, argument); } } if (!key_args.empty()) { stream << std::endl; stream << "optional arguments:" << std::endl; for (auto it = arguments.begin(); it != arguments.end(); ++it) { const _Argument & argument = *(it->second); if (!argument.is_positional) { this->print_help_argument(stream, argument); } } } } void ArgumentParser::print_help_argument(std::ostream & stream, const _Argument & argument) const { std::string key(""); if (argument.is_positional) key = argument.name; else { std::stringstream sstr; for (unsigned int i = 0; i < argument.keys.size(); ++i) { if (i != 0) sstr << ", "; sstr << argument.keys[i]; this->print_usage_nargs(sstr, argument); } key = sstr.str(); } stream << " " << std::left << std::setw(15) << key << " " << argument.help; argument.printDefault(stream); stream << std::endl; } } diff --git a/src/io/parser/cppargparse/cppargparse.hh b/src/io/parser/cppargparse/cppargparse.hh index 4a89f4c54..4608c9187 100644 --- a/src/io/parser/cppargparse/cppargparse.hh +++ b/src/io/parser/cppargparse/cppargparse.hh @@ -1,200 +1,200 @@ /** * @file cppargparse.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Apr 03 2014 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Get the commandline options and store them as short, long and others * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <iostream> #include <map> #include <string> #include <vector> #ifndef __CPPARGPARSE_HH__ #define __CPPARGPARSE_HH__ /* -------------------------------------------------------------------------- */ namespace cppargparse { /// define the types of the arguments enum ArgumentType { _string, _integer, _float, _boolean }; /// Defines how many arguments to expect enum ArgumentNargs { _one_if_possible = -1, _at_least_one = -2, _any = -3 }; /// Flags for the parse function of ArgumentParser enum ParseFlags { _no_flags = 0x0, ///< Default behavior _stop_on_not_parsed = 0x1, ///< Stop on unknown arguments _remove_parsed = 0x2 ///< Remove parsed arguments from argc argv }; /// Helps to combine parse flags inline ParseFlags operator|(const ParseFlags & a, const ParseFlags & b) { auto tmp = ParseFlags(int(a) | int(b)); return tmp; } /* -------------------------------------------------------------------------- */ /** * ArgumentParser is a class that mimics the Python argparse module */ class ArgumentParser { public: /// public definition of an argument class Argument { public: Argument() : name(std::string()) {} virtual ~Argument() = default; virtual void printself(std::ostream & stream) const = 0; template <class T> operator T() const; std::string name; }; /// constructor ArgumentParser(); /// destroy everything ~ArgumentParser(); /// add an argument with a description void addArgument(const std::string & name_or_flag, const std::string & help, int nargs = 1, ArgumentType type = _string); /// add an argument with an help and a default value template <class T> void addArgument(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, T def); /// add an argument with an help and a default + const value template <class T> void addArgument(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, T def, T cons); /// parse argc, argv void parse(int & argc, char **& argv, int flags = _stop_on_not_parsed, bool parse_help = true); /// get the last argc parsed int & getArgC() { return *(this->argc); } /// get the last argv parsed char **& getArgV() { return *(this->argv); } /// print the content in the stream void printself(std::ostream & stream) const; /// print the help text void print_help(std::ostream & stream = std::cout) const; /// print the usage text void print_usage(std::ostream & stream = std::cout) const; /// set an external function to replace the exit function from the stdlib void setExternalExitFunction(void (*external_exit)(int)) { this->external_exit = external_exit; } /// accessor for a registered argument that was parsed, throw an exception if /// the argument does not exist or was not set (parsed or default value) const Argument & operator[](const std::string & name) const; /// is the argument present bool has(const std::string &) const; /// set the parallel context to avoid multiple help messages in /// multiproc/thread cases void setParallelContext(int prank, int psize); public: /// Internal class describing the arguments struct _Argument; /// Stores that value of an argument template <class T> class ArgumentStorage; private: /// Internal function to be used by the public addArgument _Argument & _addArgument(const std::string & name_or_flag, const std::string & description, int nargs, ArgumentType type); void _exit(const std::string & msg = "", int status = 0); bool checkType(ArgumentType type, const std::string & value) const; /// function to help to print help void print_usage_nargs(std::ostream & stream, const _Argument & argument) const; /// function to help to print help void print_help_argument(std::ostream & stream, const _Argument & argument) const; private: /// public arguments storage using Arguments = std::map<std::string, Argument *>; /// internal arguments storage using _Arguments = std::map<std::string, _Argument *>; /// association key argument using ArgumentKeyMap = std::map<std::string, _Argument *>; /// position arguments using PositionalArgument = std::vector<_Argument *>; /// internal storage of arguments declared by the user _Arguments arguments; /// list of arguments successfully parsed Arguments success_parsed; /// keys associated to arguments ArgumentKeyMap key_args; /// positional arguments PositionalArgument pos_args; /// program name std::string program_name; /// exit function to use void (*external_exit)(int){nullptr}; /// Parallel context, rank and size of communicator int prank{0}, psize{1}; /// The last argc parsed (those are the modified version after parse) int * argc; /// The last argv parsed (those are the modified version after parse) char *** argv; }; } inline std::ostream & operator<<(std::ostream & stream, const cppargparse::ArgumentParser & argparse) { argparse.printself(stream); return stream; } #endif /* __CPPARGPARSE_HH__ */ #include "cppargparse_tmpl.hh" diff --git a/src/io/parser/cppargparse/cppargparse_tmpl.hh b/src/io/parser/cppargparse/cppargparse_tmpl.hh index c12727656..9dcad76df 100644 --- a/src/io/parser/cppargparse/cppargparse_tmpl.hh +++ b/src/io/parser/cppargparse/cppargparse_tmpl.hh @@ -1,240 +1,240 @@ /** * @file cppargparse_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Apr 03 2014 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Implementation of the templated part of the commandline argument * parser * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <sstream> #include <stdexcept> #ifndef __CPPARGPARSE_TMPL_HH__ #define __CPPARGPARSE_TMPL_HH__ namespace cppargparse { /* -------------------------------------------------------------------------- */ /* Argument */ /* -------------------------------------------------------------------------- */ /// internal description of arguments struct ArgumentParser::_Argument : public Argument { _Argument() : Argument(), help(std::string()) {} ~_Argument() override = default; void setValues(std::vector<std::string> & values) { for (auto it = values.begin(); it != values.end(); ++it) { this->addValue(*it); } } virtual void addValue(std::string & value) = 0; virtual void setToDefault() = 0; virtual void setToConst() = 0; std::ostream & printDefault(std::ostream & stream) const { stream << std::boolalpha; if (has_default) { stream << " (default: "; this->_printDefault(stream); stream << ")"; } if (has_const) { stream << " (const: "; this->_printConst(stream); stream << ")"; } return stream; } virtual std::ostream & _printDefault(std::ostream & stream) const = 0; virtual std::ostream & _printConst(std::ostream & stream) const = 0; std::string help; int nargs{1}; ArgumentType type{_string}; bool required{false}; bool parsed{false}; bool has_default{false}; bool has_const{false}; std::vector<std::string> keys; bool is_positional{false}; }; /* -------------------------------------------------------------------------- */ /// typed storage of the arguments template <class T> class ArgumentParser::ArgumentStorage : public ArgumentParser::_Argument { public: ArgumentStorage() : _default(T()), _const(T()), values(std::vector<T>()) {} void addValue(std::string & value) override { std::stringstream sstr(value); T t; sstr >> t; values.push_back(t); } void setToDefault() override { values.clear(); values.push_back(_default); } void setToConst() override { values.clear(); values.push_back(_const); } void printself(std::ostream & stream) const override { stream << this->name << " ="; stream << std::boolalpha; // for boolean for (auto vit = this->values.begin(); vit != this->values.end(); ++vit) { stream << " " << *vit; } } std::ostream & _printDefault(std::ostream & stream) const override { stream << _default; return stream; } std::ostream & _printConst(std::ostream & stream) const override { stream << _const; return stream; } T _default; T _const; std::vector<T> values; }; /* -------------------------------------------------------------------------- */ template <> inline void ArgumentParser::ArgumentStorage<std::string>::addValue(std::string & value) { values.push_back(value); } template <class T> struct is_vector { enum { value = false }; }; template <class T> struct is_vector<std::vector<T>> { enum { value = true }; }; /* -------------------------------------------------------------------------- */ template <class T, bool is_vector = cppargparse::is_vector<T>::value> struct cast_helper { static T cast(const ArgumentParser::Argument & arg) { const auto & _arg = dynamic_cast<const ArgumentParser::ArgumentStorage<T> &>(arg); if (_arg.values.size() == 1) { return _arg.values[0]; } else { throw std::length_error("Not enougth or too many argument where passed " "for the command line argument: " + arg.name); } } }; template <class T> struct cast_helper<T, true> { static T cast(const ArgumentParser::Argument & arg) { const auto & _arg = dynamic_cast<const ArgumentParser::ArgumentStorage<T> &>(arg); return _arg.values; } }; /* -------------------------------------------------------------------------- */ template <class T> ArgumentParser::Argument::operator T() const { return cast_helper<T>::cast(*this); } template <> inline ArgumentParser::Argument::operator const char *() const { return cast_helper<std::string>::cast(*this).c_str(); } template <> inline ArgumentParser::Argument::operator unsigned int() const { return cast_helper<int>::cast(*this); } template <class T> void ArgumentParser::addArgument(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, T def) { _Argument & arg = _addArgument(name_or_flag, help, nargs, type); dynamic_cast<ArgumentStorage<T> &>(arg)._default = def; arg.has_default = true; } template <class T> void ArgumentParser::addArgument(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, T def, T cons) { _Argument & arg = _addArgument(name_or_flag, help, nargs, type); dynamic_cast<ArgumentStorage<T> &>(arg)._default = def; arg.has_default = true; dynamic_cast<ArgumentStorage<T> &>(arg)._const = cons; arg.has_const = true; } /* -------------------------------------------------------------------------- */ template <> inline void ArgumentParser::addArgument<const char *>(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, const char * def) { this->addArgument<std::string>(name_or_flag, help, nargs, type, def); } template <> inline void ArgumentParser::addArgument<unsigned int>(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, unsigned int def) { this->addArgument<int>(name_or_flag, help, nargs, type, def); } /* -------------------------------------------------------------------------- */ template <> inline void ArgumentParser::addArgument<const char *>( const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, const char * def, const char * cons) { this->addArgument<std::string>(name_or_flag, help, nargs, type, def, cons); } template <> inline void ArgumentParser::addArgument<unsigned int>( const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type, unsigned int def, unsigned int cons) { this->addArgument<int>(name_or_flag, help, nargs, type, def, cons); } } #endif /* __AKANTU_CPPARGPARSE_TMPL_HH__ */ diff --git a/src/io/parser/input_file_parser.hh b/src/io/parser/input_file_parser.hh index 3826abca1..8de5904c9 100644 --- a/src/io/parser/input_file_parser.hh +++ b/src/io/parser/input_file_parser.hh @@ -1,268 +1,268 @@ /** * @file input_file_parser.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Tue May 19 2015 + * @date last modification: Mon Dec 18 2017 * * @brief Grammar definition for the input files * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ // Boost /* -------------------------------------------------------------------------- */ #include <boost/config/warning_disable.hpp> #include <boost/spirit/include/phoenix_bind.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_fusion.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/variant/recursive_variant.hpp> #ifndef __AKANTU_INPUT_FILE_PARSER_HH__ #define __AKANTU_INPUT_FILE_PARSER_HH__ namespace spirit = boost::spirit; namespace qi = boost::spirit::qi; namespace lbs = boost::spirit::qi::labels; namespace ascii = boost::spirit::ascii; namespace phx = boost::phoenix; namespace akantu { namespace parser { struct error_handler_ { template <typename, typename, typename, typename> struct result { using type = void; }; template <typename Iterator> void operator()(qi::info const & what, Iterator err_pos, Iterator /*first*/, Iterator /*last*/) const { spirit::classic::file_position pos = err_pos.get_position(); AKANTU_EXCEPTION("Parse error [ " << "Expecting " << what << " instead of \"" << *err_pos << "\" ]" << " in file " << pos.file << " line " << pos.line << " column " << pos.column << std::endl << "'" << err_pos.get_currentline() << "'" << std::endl << std::setw(pos.column) << " " << "^- here"); } private: }; static ParserSection & create_subsection( const ParserType & type, const boost::optional<std::string> & opt_name, const boost::optional<std::string> & opt_option, ParserSection & sect) { std::string option = ""; if (opt_option) option = *opt_option; static size_t id = 12; std::string name = "anonymous_" + std::to_string(id++); if (opt_name) name = *opt_name; ParserSection sect_tmp(name, type, option, sect); return sect.addSubSection(sect_tmp); } template <typename Iter> static bool create_parameter(boost::iterator_range<Iter> & rng, std::string & value, ParserSection & sect) { try { std::string name(rng.begin(), rng.end()); name = trim(name); spirit::classic::file_position pos = rng.begin().get_position(); ParserParameter param_tmp(name, value, sect); param_tmp.setDebugInfo(pos.file, pos.line, pos.column); sect.addParameter(param_tmp); } catch (debug::Exception & e) { return false; } return true; } static std::string concatenate(const std::string & t1, const std::string & t2) { return (t1 + t2); } /* ---------------------------------------------------------------------- */ /* Grammars definitions */ /* ---------------------------------------------------------------------- */ template <class Iterator> struct InputFileGrammar : qi::grammar<Iterator, void(), typename Skipper<Iterator>::type> { InputFileGrammar(ParserSection * sect) : InputFileGrammar::base_type(start, "input_file_grammar"), parent_section(sect) { /* clang-format off */ start = mini_section(parent_section) ; mini_section = *( entry (lbs::_r1) | section(lbs::_r1) ) ; entry = ( qi::raw[key] >> '=' > value ) [ lbs::_pass = phx::bind(&create_parameter<Iterator>, lbs::_1, lbs::_2, *lbs::_r1) ] ; section = ( qi::no_case[section_type] > qi::lexeme [ -section_name > -section_option ] ) [ lbs::_a = &phx::bind(&create_subsection, lbs::_1, phx::at_c<0>(lbs::_2), phx::at_c<1>(lbs::_2), *lbs::_r1) ] > '[' > mini_section(lbs::_a) > ']' ; section_name = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9") ; section_option = (+ascii::space >> section_name) [ lbs::_val = lbs::_2 ] ; key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9") ; value = ( mono_line_value [ lbs::_a = phx::bind(&concatenate, lbs::_a, lbs::_1) ] > *( '\\' > mono_line_value [ lbs::_a = phx::bind(&concatenate, lbs::_a, lbs::_1) ] ) ) [ lbs::_val = lbs::_a ] ; mono_line_value = qi::lexeme [ +(qi::char_ - (qi::char_('=') | spirit::eol | '#' | ';' | '\\')) ] ; skipper = ascii::space | "#" >> *(qi::char_ - spirit::eol) ; /* clang-format on */ #define AKANTU_SECTION_TYPE_ADD(r, data, elem) \ (BOOST_PP_STRINGIZE(elem), BOOST_PP_CAT(ParserType::_, elem)) section_type.add BOOST_PP_SEQ_FOR_EACH(AKANTU_SECTION_TYPE_ADD, _, AKANTU_SECTION_TYPES); #undef AKANTU_SECTION_TYPE_ADD #if !defined(AKANTU_NDEBUG) && defined(AKANTU_CORE_CXX_11) phx::function<error_handler_> const error_handler = error_handler_(); qi::on_error<qi::fail>(start, error_handler(lbs::_4, lbs::_3, lbs::_1, lbs::_2)); #endif section.name("section"); section_name.name("section-name"); section_option.name("section-option"); mini_section.name("section-content"); entry.name("parameter"); key.name("parameter-name"); value.name("parameter-value"); section_type.name("section-types-list"); mono_line_value.name("mono-line-value"); #if !defined AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDebug)) { // qi::debug(section); qi::debug(section_name); qi::debug(section_option); // qi::debug(mini_section); // qi::debug(entry); qi::debug(key); qi::debug(value); qi::debug(mono_line_value); } #endif } const std::string & getErrorMessage() const { return error_message; }; using skipper_type = typename Skipper<Iterator>::type; skipper_type skipper; private: std::string error_message; qi::rule<Iterator, void(ParserSection *), skipper_type> mini_section; qi::rule<Iterator, void(ParserSection *), qi::locals<ParserSection *>, skipper_type> section; qi::rule<Iterator, void(), skipper_type> start; qi::rule<Iterator, std::string()> section_name; qi::rule<Iterator, std::string()> section_option; qi::rule<Iterator, void(ParserSection *), skipper_type> entry; qi::rule<Iterator, std::string(), skipper_type> key; qi::rule<Iterator, std::string(), qi::locals<std::string>, skipper_type> value; qi::rule<Iterator, std::string(), skipper_type> mono_line_value; qi::symbols<char, ParserType> section_type; ParserSection * parent_section; }; } } // akantu #endif /* __AKANTU_INPUT_FILE_PARSER_HH__ */ diff --git a/src/io/parser/parameter_registry.cc b/src/io/parser/parameter_registry.cc index 1e63f3127..69f2a0c47 100644 --- a/src/io/parser/parameter_registry.cc +++ b/src/io/parser/parameter_registry.cc @@ -1,154 +1,154 @@ /** * @file parameter_registry.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Wed Nov 13 2013 - * @date last modification: Thu Nov 19 2015 + * @date creation: Wed May 04 2016 + * @date last modification: Thu Feb 01 2018 * * @brief Parameter Registry and derived classes implementation * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <utility> #include "parameter_registry.hh" /* -------------------------------------------------------------------------- */ namespace akantu { Parameter::Parameter() : name(""), description("") {} /* -------------------------------------------------------------------------- */ Parameter::Parameter(std::string name, std::string description, ParameterAccessType param_type) : name(std::move(name)), description(std::move(description)), param_type(param_type) {} /* -------------------------------------------------------------------------- */ bool Parameter::isWritable() const { return param_type & _pat_writable; } /* -------------------------------------------------------------------------- */ bool Parameter::isReadable() const { return param_type & _pat_readable; } /* -------------------------------------------------------------------------- */ bool Parameter::isInternal() const { return param_type & _pat_internal; } /* -------------------------------------------------------------------------- */ bool Parameter::isParsable() const { return param_type & _pat_parsable; } /* -------------------------------------------------------------------------- */ void Parameter::setAccessType(ParameterAccessType ptype) { this->param_type = ptype; } /* -------------------------------------------------------------------------- */ void Parameter::printself(std::ostream & stream) const { stream << " "; if (isInternal()) stream << "iii"; else { if (isReadable()) stream << "r"; else stream << "-"; if (isWritable()) stream << "w"; else stream << "-"; if (isParsable()) stream << "p"; else stream << "-"; } stream << " "; std::stringstream sstr; sstr << name; UInt width = std::max(int(10 - sstr.str().length()), 0); sstr.width(width); if (description != "") { sstr << " [" << description << "]"; } stream << sstr.str(); width = std::max(int(50 - sstr.str().length()), 0); stream.width(width); stream << " : "; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ ParameterRegistry::ParameterRegistry() = default; /* -------------------------------------------------------------------------- */ ParameterRegistry::~ParameterRegistry() { std::map<std::string, Parameter *>::iterator it, end; for (it = params.begin(); it != params.end(); ++it) { delete it->second; it->second = NULL; } this->params.clear(); } /* -------------------------------------------------------------------------- */ void ParameterRegistry::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; Parameters::const_iterator it; for (it = params.begin(); it != params.end(); ++it) { stream << space; it->second->printself(stream); } SubRegisteries::const_iterator sub_it; for (sub_it = sub_registries.begin(); sub_it != sub_registries.end(); ++sub_it) { stream << space << "Registry [" << std::endl; sub_it->second->printself(stream, indent + 1); stream << space << "]"; } } /* -------------------------------------------------------------------------- */ void ParameterRegistry::registerSubRegistry(const ID & id, ParameterRegistry & registry) { sub_registries[id] = ®istry; } /* -------------------------------------------------------------------------- */ void ParameterRegistry::setParameterAccessType(const std::string & name, ParameterAccessType ptype) { auto it = params.find(name); if (it == params.end()) AKANTU_CUSTOM_EXCEPTION(debug::ParameterUnexistingException(name, *this)); Parameter & param = *(it->second); param.setAccessType(ptype); } } // akantu diff --git a/src/io/parser/parameter_registry.hh b/src/io/parser/parameter_registry.hh index af649bdc8..733883f78 100644 --- a/src/io/parser/parameter_registry.hh +++ b/src/io/parser/parameter_registry.hh @@ -1,222 +1,221 @@ /** * @file parameter_registry.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Aug 09 2012 - * @date last modification: Thu Dec 17 2015 + * @date last modification: Tue Jan 30 2018 * * @brief Interface of the parameter registry * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PARAMETER_REGISTRY_HH__ #define __AKANTU_PARAMETER_REGISTRY_HH__ namespace akantu { class ParserParameter; } namespace akantu { /* -------------------------------------------------------------------------- */ /// Defines the access modes of parsable parameters enum ParameterAccessType { _pat_internal = 0x0001, _pat_writable = 0x0010, _pat_readable = 0x0100, _pat_modifiable = 0x0110, //<_pat_readable | _pat_writable, _pat_parsable = 0x1000, _pat_parsmod = 0x1110 //< _pat_parsable | _pat_modifiable }; /// Bit-wise operator between access modes inline ParameterAccessType operator|(const ParameterAccessType & a, const ParameterAccessType & b) { auto tmp = ParameterAccessType(UInt(a) | UInt(b)); return tmp; } /* -------------------------------------------------------------------------- */ template <typename T> class ParameterTyped; /** * Interface for the Parameter */ class Parameter { public: Parameter(); Parameter(std::string name, std::string description, ParameterAccessType param_type); virtual ~Parameter() = default; /* ------------------------------------------------------------------------ */ bool isInternal() const; bool isWritable() const; bool isReadable() const; bool isParsable() const; void setAccessType(ParameterAccessType ptype); /* ------------------------------------------------------------------------ */ template <typename T, typename V> void set(const V & value); virtual void setAuto(const ParserParameter & param); template <typename T> T & get(); template <typename T> const T & get() const; virtual inline operator Real() const { throw std::bad_cast(); }; template <typename T> inline operator T() const; /* ------------------------------------------------------------------------ */ virtual void printself(std::ostream & stream) const; virtual const std::type_info & type() const = 0; protected: /// Returns const instance of templated sub-class ParameterTyped template <typename T> const ParameterTyped<T> & getParameterTyped() const; /// Returns instance of templated sub-class ParameterTyped template <typename T> ParameterTyped<T> & getParameterTyped(); protected: /// Name of parameter std::string name; private: /// Description of parameter std::string description; /// Type of access ParameterAccessType param_type{_pat_internal}; }; /* -------------------------------------------------------------------------- */ /* Typed Parameter */ /* -------------------------------------------------------------------------- */ /** * Type parameter transfering a ParserParameter (string: string) to a typed * parameter in the memory of the p */ template <typename T> class ParameterTyped : public Parameter { public: ParameterTyped(std::string name, std::string description, ParameterAccessType param_type, T & param); /* ------------------------------------------------------------------------ */ template <typename V> void setTyped(const V & value); void setAuto(const ParserParameter & param) override; T & getTyped(); const T & getTyped() const; void printself(std::ostream & stream) const override; inline operator Real() const override; inline const std::type_info & type() const override { return typeid(T); } private: /// Value of parameter T & param; }; /* -------------------------------------------------------------------------- */ /* Parsable Interface */ /* -------------------------------------------------------------------------- */ /// Defines interface for classes to manipulate parsable parameters class ParameterRegistry { public: ParameterRegistry(); virtual ~ParameterRegistry(); /* ------------------------------------------------------------------------ */ /// Add parameter to the params map template <typename T> void registerParam(std::string name, T & variable, ParameterAccessType type, const std::string & description = ""); /// Add parameter to the params map (with default value) template <typename T> void registerParam(std::string name, T & variable, const T & default_value, ParameterAccessType type, const std::string & description = ""); /*------------------------------------------------------------------------- */ protected: void registerSubRegistry(const ID & id, ParameterRegistry & registry); /* ------------------------------------------------------------------------ */ public: /// Set value to a parameter (with possible different type) template <typename T, typename V> void setMixed(const std::string & name, const V & value); /// Set value to a parameter template <typename T> void set(const std::string & name, const T & value); /// Get value of a parameter inline const Parameter & get(const std::string & name) const; std::vector<ID> listParameters() const { std::vector<ID> params; for (auto & pair : this->params) params.push_back(pair.first); return params; } std::vector<ID> listSubRegisteries() const { std::vector<ID> subs; for (auto & pair : this->sub_registries) subs.push_back(pair.first); return subs; } protected: template <typename T> T & get_(const std::string & name); protected: void setParameterAccessType(const std::string & name, ParameterAccessType ptype); /* ------------------------------------------------------------------------ */ virtual void printself(std::ostream & stream, int indent) const; protected: /// Parameters map using Parameters = std::map<std::string, Parameter *>; Parameters params; /// list of sub-registries using SubRegisteries = std::map<std::string, ParameterRegistry *>; SubRegisteries sub_registries; /// should accessor check in sub registries bool consisder_sub{true}; }; } // akantu #include "parameter_registry_tmpl.hh" #endif /* __AKANTU_PARAMETER_REGISTRY_HH__ */ diff --git a/src/io/parser/parameter_registry_tmpl.hh b/src/io/parser/parameter_registry_tmpl.hh index 935338739..dd9f00d4d 100644 --- a/src/io/parser/parameter_registry_tmpl.hh +++ b/src/io/parser/parameter_registry_tmpl.hh @@ -1,391 +1,390 @@ /** * @file parameter_registry_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Thu Aug 09 2012 - * @date last modification: Fri Mar 27 2015 + * @date creation: Wed May 04 2016 + * @date last modification: Tue Jan 30 2018 * - * @brief implementation of the templated part of ParameterRegistry class and + * @brief implementation of the templated part of ParameterRegistry class and * the derivated ones * * @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) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_error.hh" #include "aka_iterators.hh" #include "parameter_registry.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <string> #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PARAMETER_REGISTRY_TMPL_HH__ #define __AKANTU_PARAMETER_REGISTRY_TMPL_HH__ namespace akantu { namespace debug { class ParameterException : public Exception { public: ParameterException(const std::string & name, const std::string & message) : Exception(message), name(name) {} const std::string & name; }; class ParameterUnexistingException : public ParameterException { public: ParameterUnexistingException(const std::string & name, const ParameterRegistry & registery) : ParameterException( name, "Parameter " + name + " does not exists in this scope") { auto && params = registery.listParameters(); this->_info = std::accumulate(params.begin(), params.end(), this->_info + "\n Possible parameters are: ", [](auto && str, auto && param) { static auto first = true; auto && ret = str + (first ? " " : ", ") + param; first = false; return ret; }); } }; class ParameterAccessRightException : public ParameterException { public: ParameterAccessRightException(const std::string & name, const std::string & perm) : ParameterException(name, "Parameter " + name + " is not " + perm) {} }; class ParameterWrongTypeException : public ParameterException { public: ParameterWrongTypeException(const std::string & name, const std::type_info & wrong_type, const std::type_info & type) : ParameterException(name, "Parameter " + name + " type error, cannot convert " + debug::demangle(type.name()) + " to " + debug::demangle(wrong_type.name())) {} }; } // namespace debug /* -------------------------------------------------------------------------- */ template <typename T> const ParameterTyped<T> & Parameter::getParameterTyped() const { try { const auto & tmp = dynamic_cast<const ParameterTyped<T> &>(*this); return tmp; } catch (std::bad_cast &) { AKANTU_CUSTOM_EXCEPTION( debug::ParameterWrongTypeException(name, typeid(T), this->type())); } } /* -------------------------------------------------------------------------- */ template <typename T> ParameterTyped<T> & Parameter::getParameterTyped() { try { auto & tmp = dynamic_cast<ParameterTyped<T> &>(*this); return tmp; } catch (std::bad_cast &) { AKANTU_CUSTOM_EXCEPTION( debug::ParameterWrongTypeException(name, typeid(T), this->type())); } } /* ------------------------------------------------------------------------ */ template <typename T, typename V> void Parameter::set(const V & value) { if (!(isWritable())) AKANTU_CUSTOM_EXCEPTION( debug::ParameterAccessRightException(name, "writable")); ParameterTyped<T> & typed_param = getParameterTyped<T>(); typed_param.setTyped(value); } /* ------------------------------------------------------------------------ */ inline void Parameter::setAuto(__attribute__((unused)) const ParserParameter & value) { if (!(isParsable())) AKANTU_CUSTOM_EXCEPTION( debug::ParameterAccessRightException(name, "parsable")); } /* -------------------------------------------------------------------------- */ template <typename T> const T & Parameter::get() const { if (!(isReadable())) AKANTU_CUSTOM_EXCEPTION( debug::ParameterAccessRightException(name, "readable")); const ParameterTyped<T> & typed_param = getParameterTyped<T>(); return typed_param.getTyped(); } /* -------------------------------------------------------------------------- */ template <typename T> T & Parameter::get() { ParameterTyped<T> & typed_param = getParameterTyped<T>(); if (!(isReadable()) || !(this->isWritable())) AKANTU_CUSTOM_EXCEPTION( debug::ParameterAccessRightException(name, "accessible")); return typed_param.getTyped(); } /* -------------------------------------------------------------------------- */ template <typename T> inline Parameter::operator T() const { return this->get<T>(); } /* -------------------------------------------------------------------------- */ template <typename T> ParameterTyped<T>::ParameterTyped(std::string name, std::string description, ParameterAccessType param_type, T & param) : Parameter(name, description, param_type), param(param) {} /* -------------------------------------------------------------------------- */ template <typename T> template <typename V> void ParameterTyped<T>::setTyped(const V & value) { param = value; } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParameterTyped<T>::setAuto(const ParserParameter & value) { Parameter::setAuto(value); param = static_cast<T>(value); } /* -------------------------------------------------------------------------- */ template <> inline void ParameterTyped<std::string>::setAuto(const ParserParameter & value) { Parameter::setAuto(value); param = value.getValue(); } /* -------------------------------------------------------------------------- */ template <> inline void ParameterTyped<Vector<Real>>::setAuto(const ParserParameter & in_param) { Parameter::setAuto(in_param); Vector<Real> tmp = in_param; if (param.size() == 0) { param = tmp; } else { for (UInt i = 0; i < param.size(); ++i) { param(i) = tmp(i); } } } /* -------------------------------------------------------------------------- */ template <> inline void ParameterTyped<Matrix<Real>>::setAuto(const ParserParameter & in_param) { Parameter::setAuto(in_param); Matrix<Real> tmp = in_param; if (param.size() == 0) { param = tmp; } else { for (UInt i = 0; i < param.rows(); ++i) { for (UInt j = 0; j < param.cols(); ++j) { param(i, j) = tmp(i, j); } } } } /* -------------------------------------------------------------------------- */ template <typename T> const T & ParameterTyped<T>::getTyped() const { return param; } /* -------------------------------------------------------------------------- */ template <typename T> T & ParameterTyped<T>::getTyped() { return param; } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParameterTyped<T>::printself(std::ostream & stream) const { Parameter::printself(stream); stream << param << "\n"; } /* -------------------------------------------------------------------------- */ template <typename T> class ParameterTyped<std::vector<T>> : public Parameter { public: ParameterTyped(std::string name, std::string description, ParameterAccessType param_type, std::vector<T> & param) : Parameter(name, description, param_type), param(param) {} /* ------------------------------------------------------------------------ */ template <typename V> void setTyped(const V & value) { param = value; } void setAuto(const ParserParameter & value) override { Parameter::setAuto(value); param.clear(); const std::vector<T> & tmp = value; for (auto && z : tmp) { param.emplace_back(z); } } std::vector<T> & getTyped() { return param; } const std::vector<T> & getTyped() const { return param; } void printself(std::ostream & stream) const override { Parameter::printself(stream); stream << "[ "; for (auto && v : param) stream << v << " "; stream << "]\n"; } inline const std::type_info & type() const override { return typeid(std::vector<T>); } private: /// Value of parameter std::vector<T> & param; }; /* ------o-------------------------------------------------------------------- */ template <> inline void ParameterTyped<bool>::printself(std::ostream & stream) const { Parameter::printself(stream); stream << std::boolalpha << param << "\n"; } /* -------------------------------------------------------------------------- */ template <typename T> void ParameterRegistry::registerParam(std::string name, T & variable, ParameterAccessType type, const std::string & description) { auto it = params.find(name); if (it != params.end()) AKANTU_CUSTOM_EXCEPTION(debug::ParameterException( name, "Parameter named " + name + " already registered.")); auto * param = new ParameterTyped<T>(name, description, type, variable); params[name] = param; } /* -------------------------------------------------------------------------- */ template <typename T> void ParameterRegistry::registerParam(std::string name, T & variable, const T & default_value, ParameterAccessType type, const std::string & description) { variable = default_value; registerParam(name, variable, type, description); } /* -------------------------------------------------------------------------- */ template <typename T, typename V> void ParameterRegistry::setMixed(const std::string & name, const V & value) { auto it = params.find(name); if (it == params.end()) { if (consisder_sub) { for (auto it = sub_registries.begin(); it != sub_registries.end(); ++it) { it->second->setMixed<T>(name, value); } } else { AKANTU_CUSTOM_EXCEPTION(debug::ParameterUnexistingException(name, *this)); } } else { Parameter & param = *(it->second); param.set<T>(value); } } /* -------------------------------------------------------------------------- */ template <typename T> void ParameterRegistry::set(const std::string & name, const T & value) { this->template setMixed<T>(name, value); } /* -------------------------------------------------------------------------- */ template <typename T> T & ParameterRegistry::get_(const std::string & name) { auto it = params.find(name); if (it == params.end()) { if (consisder_sub) { for (auto it = sub_registries.begin(); it != sub_registries.end(); ++it) { try { return it->second->get_<T>(name); } catch (...) { } } } // nothing was found not even in sub registries AKANTU_CUSTOM_EXCEPTION(debug::ParameterUnexistingException(name, *this)); } Parameter & param = *(it->second); return param.get<T>(); } /* -------------------------------------------------------------------------- */ const Parameter & ParameterRegistry::get(const std::string & name) const { auto it = params.find(name); if (it == params.end()) { if (consisder_sub) { for (auto it = sub_registries.begin(); it != sub_registries.end(); ++it) { try { return it->second->get(name); } catch (...) { } } } // nothing was found not even in sub registries AKANTU_CUSTOM_EXCEPTION(debug::ParameterUnexistingException(name, *this)); } Parameter & param = *(it->second); return param; } /* -------------------------------------------------------------------------- */ namespace { namespace details { template <class T, class R, class Enable = void> struct CastHelper { static R convert(const T &) { throw std::bad_cast(); } }; template <class T, class R> struct CastHelper<T, R, std::enable_if_t<std::is_convertible<T, R>::value>> { static R convert(const T & val) { return val; } }; } // namespace details } // namespace template <typename T> inline ParameterTyped<T>::operator Real() const { if (not isReadable()) AKANTU_CUSTOM_EXCEPTION( debug::ParameterAccessRightException(name, "accessible")); return details::CastHelper<T, Real>::convert(param); } } // namespace akantu #endif /* __AKANTU_PARAMETER_REGISTRY_TMPL_HH__ */ diff --git a/src/io/parser/parsable.cc b/src/io/parser/parsable.cc index 89b41a458..c779bd11f 100644 --- a/src/io/parser/parsable.cc +++ b/src/io/parser/parsable.cc @@ -1,109 +1,110 @@ /** * @file parsable.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Thu Nov 19 2015 + * @date last modification: Thu Feb 08 2018 * * @brief Parsable implementation * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "parsable.hh" #include "aka_random_generator.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Parsable::Parsable(const ParserType & section_type, const ID & id) : section_type(section_type), pid(id) { this->consisder_sub = false; } /* -------------------------------------------------------------------------- */ Parsable::~Parsable() = default; /* -------------------------------------------------------------------------- */ void Parsable::registerSubSection(const ParserType & type, const std::string & name, Parsable & sub_section) { SubSectionKey key(type, name); sub_sections[key] = &sub_section; this->registerSubRegistry(name, sub_section); } /* -------------------------------------------------------------------------- */ void Parsable::parseParam(const ParserParameter & in_param) { auto it = params.find(in_param.getName()); if (it == params.end()) { if (Parser::isPermissive()) { AKANTU_DEBUG_WARNING("No parameter named " << in_param.getName() << " registered in " << pid << "."); return; } else AKANTU_EXCEPTION("No parameter named " << in_param.getName() << " registered in " << pid << "."); } Parameter & param = *(it->second); param.setAuto(in_param); } /* -------------------------------------------------------------------------- */ void Parsable::parseSection(const ParserSection & section) { if (section_type != section.getType()) AKANTU_EXCEPTION("The object " << pid << " is meant to parse section of type " << section_type << ", so it cannot parse section of type " << section.getType()); auto params = section.getParameters(); auto it = params.first; for (; it != params.second; ++it) { parseParam(*it); } auto sit = section.getSubSections().first; for (; sit != section.getSubSections().second; ++sit) { parseSubSection(*sit); } } /* -------------------------------------------------------------------------- */ void Parsable::parseSubSection(const ParserSection & section) { SubSectionKey key(section.getType(), section.getName()); auto it = sub_sections.find(key); if (it != sub_sections.end()) { it->second->parseSection(section); } else if (!Parser::isPermissive()) { AKANTU_EXCEPTION("No parsable defined for sub sections of type <" << key.first << "," << key.second << "> in " << pid); } else { AKANTU_DEBUG_WARNING("No parsable defined for sub sections of type <" << key.first << "," << key.second << "> in " << pid); } } } // akantu diff --git a/src/io/parser/parsable.hh b/src/io/parser/parsable.hh index 5eb45a4e8..542c64769 100644 --- a/src/io/parser/parsable.hh +++ b/src/io/parser/parsable.hh @@ -1,74 +1,73 @@ /** - * @file parameter_registry.hh + * @file parsable.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Aug 09 2012 - * @date last modification: Thu Dec 17 2015 + * @date last modification: Fri Dec 08 2017 * * @brief Interface of the parameter registry * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "parameter_registry.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PARSABLE_HH__ #define __AKANTU_PARSABLE_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Parsable Interface */ /* -------------------------------------------------------------------------- */ /// Defines interface for classes to manipulate parsable parameters class Parsable : public ParameterRegistry { public: Parsable(const ParserType & section_type, const ID & id = std::string()); ~Parsable() override; /// Add subsection to the sub_sections map void registerSubSection(const ParserType & type, const std::string & name, Parsable & sub_section); /* ------------------------------------------------------------------------ */ public: virtual void parseSection(const ParserSection & section); virtual void parseSubSection(const ParserSection & section); virtual void parseParam(const ParserParameter & parameter); private: ParserType section_type; /// ID of parsable object ID pid; using SubSectionKey = std::pair<ParserType, std::string>; using SubSections = std::map<SubSectionKey, Parsable *>; /// Subsections map SubSections sub_sections; }; } // namespace akantu #endif /* __AKANTU_PARSABLE_HH__ */ diff --git a/src/io/parser/parser.cc b/src/io/parser/parser.cc index b21c0db0f..30b34ad8c 100644 --- a/src/io/parser/parser.cc +++ b/src/io/parser/parser.cc @@ -1,101 +1,101 @@ /** * @file parser.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Wed Jan 13 2016 + * @date last modification: Thu Feb 01 2018 * * @brief implementation of the parser * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ // STL #include <fstream> #include <iomanip> #include <map> /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ParserSection::~ParserSection() { this->clean(); } /* -------------------------------------------------------------------------- */ ParserParameter & ParserSection::addParameter(const ParserParameter & param) { if (parameters.find(param.getName()) != parameters.end()) AKANTU_EXCEPTION("The parameter \"" + param.getName() + "\" is already defined in this section"); return (parameters .insert(std::pair<std::string, ParserParameter>(param.getName(), param)) .first->second); } /* -------------------------------------------------------------------------- */ ParserSection & ParserSection::addSubSection(const ParserSection & section) { return ((sub_sections_by_type.insert(std::pair<ParserType, ParserSection>( section.getType(), section))) ->second); } /* -------------------------------------------------------------------------- */ std::string Parser::getLastParsedFile() const { return last_parsed_file; } /* -------------------------------------------------------------------------- */ void ParserSection::printself(std::ostream & stream, unsigned int indent) const { std::string space; std::string ind = AKANTU_INDENT; for (unsigned int i = 0; i < indent; i++, space += ind) ; stream << space << "Section(" << this->type << ") " << this->name << (option != "" ? (" " + option) : "") << " [" << std::endl; if (!this->parameters.empty()) { stream << space << ind << "Parameters [" << std::endl; auto pit = this->parameters.begin(); for (; pit != this->parameters.end(); ++pit) { stream << space << ind << " + "; pit->second.printself(stream); stream << std::endl; } stream << space << ind << "]" << std::endl; } if (!this->sub_sections_by_type.empty()) { stream << space << ind << "Subsections [" << std::endl; auto sit = this->sub_sections_by_type.begin(); for (; sit != this->sub_sections_by_type.end(); ++sit) sit->second.printself(stream, indent + 2); stream << std::endl; stream << space << ind << "]" << std::endl; } stream << space << "]" << std::endl; } } // akantu diff --git a/src/io/parser/parser.hh b/src/io/parser/parser.hh index d97850eef..c762f0493 100644 --- a/src/io/parser/parser.hh +++ b/src/io/parser/parser.hh @@ -1,506 +1,506 @@ /** * @file parser.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Wed Jan 13 2016 + * @date last modification: Fri Dec 08 2017 * * @brief File parser interface * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_random_generator.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PARSER_HH__ #define __AKANTU_PARSER_HH__ namespace akantu { // clang-format off #define AKANTU_SECTION_TYPES \ (cohesive_inserter) \ (contact) \ (embedded_interface) \ (friction) \ (global) \ (heat) \ (integration_scheme) \ (material) \ (mesh) \ (model) \ (model_solver) \ (neighborhood) \ (neighborhoods) \ (non_linear_solver) \ (non_local) \ (rules) \ (solver) \ (time_step_solver) \ (user) \ (weight_function) \ (not_defined) // clang-format on /// Defines the possible section types AKANTU_ENUM_DECLARE(ParserType, AKANTU_SECTION_TYPES) AKANTU_ENUM_OUTPUT_STREAM(ParserType, AKANTU_SECTION_TYPES) AKANTU_ENUM_INPUT_STREAM(ParserType, AKANTU_SECTION_TYPES) /// Defines the possible search contexts/scopes (for parameter search) enum ParserParameterSearchCxt { _ppsc_current_scope = 0x1, _ppsc_parent_scope = 0x2, _ppsc_current_and_parent_scope = 0x3 }; /* ------------------------------------------------------------------------ */ /* Parameters Class */ /* ------------------------------------------------------------------------ */ class ParserSection; /// @brief The ParserParameter objects represent the end of tree branches as /// they /// are the different informations contained in the input file. class ParserParameter { public: ParserParameter() : name(std::string()), value(std::string()), dbg_filename(std::string()) { } ParserParameter(const std::string & name, const std::string & value, const ParserSection & parent_section) : parent_section(&parent_section), name(name), value(value), dbg_filename(std::string()) {} ParserParameter(const ParserParameter & param) = default; virtual ~ParserParameter() = default; /// Get parameter name const std::string & getName() const { return name; } /// Get parameter value const std::string & getValue() const { return value; } /// Set info for debug output void setDebugInfo(const std::string & filename, UInt line, UInt column) { dbg_filename = filename; dbg_line = line; dbg_column = column; } template <typename T> inline operator T() const; // template <typename T> inline operator Vector<T>() const; // template <typename T> inline operator Matrix<T>() const; /// Print parameter info in stream void printself(std::ostream & stream, __attribute__((unused)) unsigned int indent = 0) const { stream << name << ": " << value << " (" << dbg_filename << ":" << dbg_line << ":" << dbg_column << ")"; } private: void setParent(const ParserSection & sect) { parent_section = § } friend class ParserSection; private: /// Pointer to the parent section const ParserSection * parent_section{nullptr}; /// Name of the parameter std::string name; /// Value of the parameter std::string value; /// File for debug output std::string dbg_filename; /// Position of parameter in parsed file UInt dbg_line, dbg_column; }; /* ------------------------------------------------------------------------ */ /* Sections Class */ /* ------------------------------------------------------------------------ */ /// ParserSection represents a branch of the parsing tree. class ParserSection { public: using SubSections = std::multimap<ParserType, ParserSection>; using Parameters = std::map<std::string, ParserParameter>; private: using const_section_iterator_ = SubSections::const_iterator; public: /* ------------------------------------------------------------------------ */ /* SubSection iterator */ /* ------------------------------------------------------------------------ */ /// Iterator on sections class const_section_iterator { public: using iterator_category = std::forward_iterator_tag; using value_type = ParserSection; using pointer = ParserSection *; using reference = ParserSection &; const_section_iterator() = default; const_section_iterator(const const_section_iterator_ & it) : it(it) {} const_section_iterator(const const_section_iterator & other) = default; const_section_iterator & operator=(const const_section_iterator & other) = default; const ParserSection & operator*() const { return it->second; } const ParserSection * operator->() const { return &(it->second); } bool operator==(const const_section_iterator & other) const { return it == other.it; } bool operator!=(const const_section_iterator & other) const { return it != other.it; } const_section_iterator & operator++() { ++it; return *this; } const_section_iterator operator++(int) { const_section_iterator tmp = *this; operator++(); return tmp; } private: const_section_iterator_ it; }; /* ------------------------------------------------------------------------ */ /* Parameters iterator */ /* ------------------------------------------------------------------------ */ /// Iterator on parameters class const_parameter_iterator { public: const_parameter_iterator(const const_parameter_iterator & other) = default; const_parameter_iterator(const Parameters::const_iterator & it) : it(it) {} const_parameter_iterator & operator=(const const_parameter_iterator & other) { if (this != &other) { it = other.it; } return *this; } const ParserParameter & operator*() const { return it->second; } const ParserParameter * operator->() { return &(it->second); }; bool operator==(const const_parameter_iterator & other) const { return it == other.it; } bool operator!=(const const_parameter_iterator & other) const { return it != other.it; } const_parameter_iterator & operator++() { ++it; return *this; } const_parameter_iterator operator++(int) { const_parameter_iterator tmp = *this; operator++(); return tmp; } private: Parameters::const_iterator it; }; /* ---------------------------------------------------------------------- */ ParserSection() : name(std::string()) {} ParserSection(const std::string & name, ParserType type) : parent_section(nullptr), name(name), type(type) {} ParserSection(const std::string & name, ParserType type, const std::string & option, const ParserSection & parent_section) : parent_section(&parent_section), name(name), type(type), option(option) {} ParserSection(const ParserSection & section) : parent_section(section.parent_section), name(section.name), type(section.type), option(section.option), parameters(section.parameters), sub_sections_by_type(section.sub_sections_by_type) { setChldrenPointers(); } ParserSection & operator=(const ParserSection & other) { if (&other != this) { parent_section = other.parent_section; name = other.name; type = other.type; option = other.option; parameters = other.parameters; sub_sections_by_type = other.sub_sections_by_type; setChldrenPointers(); } return *this; } virtual ~ParserSection(); virtual void printself(std::ostream & stream, unsigned int indent = 0) const; /* ---------------------------------------------------------------------- */ /* Creation functions */ /* ---------------------------------------------------------------------- */ public: ParserParameter & addParameter(const ParserParameter & param); ParserSection & addSubSection(const ParserSection & section); protected: /// Clean ParserSection content void clean() { parameters.clear(); sub_sections_by_type.clear(); } private: void setChldrenPointers() { for (auto && param_pair : this->parameters) param_pair.second.setParent(*this); for (auto && sub_sect_pair : this->sub_sections_by_type) sub_sect_pair.second.setParent(*this); } /* ---------------------------------------------------------------------- */ /* Accessors */ /* ---------------------------------------------------------------------- */ public: class SubSectionsRange : public std::pair<const_section_iterator, const_section_iterator> { public: SubSectionsRange(const const_section_iterator & first, const const_section_iterator & second) : std::pair<const_section_iterator, const_section_iterator>(first, second) {} auto begin() { return this->first; } auto end() { return this->second; } }; /// Get begin and end iterators on subsections of certain type auto getSubSections(ParserType type = ParserType::_not_defined) const { if (type != ParserType::_not_defined) { auto range = sub_sections_by_type.equal_range(type); return SubSectionsRange(range.first, range.second); } else { return SubSectionsRange(sub_sections_by_type.begin(), sub_sections_by_type.end()); } } /// Get number of subsections of certain type UInt getNbSubSections(ParserType type = ParserType::_not_defined) const { if (type != ParserType::_not_defined) { return this->sub_sections_by_type.count(type); } else { return this->sub_sections_by_type.size(); } } /// Get begin and end iterators on parameters auto getParameters() const { return std::pair<const_parameter_iterator, const_parameter_iterator>( parameters.begin(), parameters.end()); } /* ---------------------------------------------------------------------- */ /// Get parameter within specified context const ParserParameter & getParameter( const std::string & name, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { Parameters::const_iterator it; if (search_ctx & _ppsc_current_scope) it = parameters.find(name); if (it == parameters.end()) { if ((search_ctx & _ppsc_parent_scope) && parent_section) return parent_section->getParameter(name, search_ctx); else { AKANTU_SILENT_EXCEPTION( "The parameter " << name << " has not been found in the specified context"); } } return it->second; } /* ------------------------------------------------------------------------ */ /// Get parameter within specified context, with a default value in case the /// parameter does not exists template <class T> const T getParameter( const std::string & name, const T & default_value, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { try { T tmp = this->getParameter(name, search_ctx); return tmp; } catch (debug::Exception &) { return default_value; } } /* ------------------------------------------------------------------------ */ /// Check if parameter exists within specified context bool hasParameter( const std::string & name, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { Parameters::const_iterator it; if (search_ctx & _ppsc_current_scope) it = parameters.find(name); if (it == parameters.end()) { if ((search_ctx & _ppsc_parent_scope) && parent_section) return parent_section->hasParameter(name, search_ctx); else { return false; } } return true; } /* -------------------------------------------------------------------------- */ /// Get value of given parameter in context template <class T> T getParameterValue( const std::string & name, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { const ParserParameter & tmp_param = getParameter(name, search_ctx); T t = tmp_param; return t; } /* -------------------------------------------------------------------------- */ /// Get section name const std::string getName() const { return name; } /// Get section type ParserType getType() const { return type; } /// Get section option const std::string getOption(const std::string & def = "") const { return option != "" ? option : def; } protected: void setParent(const ParserSection & sect) { parent_section = § } /* ---------------------------------------------------------------------- */ /* Members */ /* ---------------------------------------------------------------------- */ private: /// Pointer to the parent section const ParserSection * parent_section{nullptr}; /// Name of section std::string name; /// Type of section, see AKANTU_SECTION_TYPES ParserType type{ParserType::_not_defined}; /// Section option std::string option; /// Map of parameters in section Parameters parameters; /// Multi-map of subsections SubSections sub_sections_by_type; }; /* ------------------------------------------------------------------------ */ /* Parser Class */ /* ------------------------------------------------------------------------ */ /// Root of parsing tree, represents the global ParserSection class Parser : public ParserSection { public: Parser() : ParserSection("global", ParserType::_global) {} void parse(const std::string & filename); std::string getLastParsedFile() const; static bool isPermissive() { return permissive_parser; } public: /// Parse real scalar static Real parseReal(const std::string & value, const ParserSection & section); /// Parse real vector static Vector<Real> parseVector(const std::string & value, const ParserSection & section); /// Parse real matrix static Matrix<Real> parseMatrix(const std::string & value, const ParserSection & section); /// Parse real random parameter static RandomParameter<Real> parseRandomParameter(const std::string & value, const ParserSection & section); protected: /// General parse function template <class T, class Grammar> static T parseType(const std::string & value, Grammar & grammar); protected: // friend class Parsable; static bool permissive_parser; std::string last_parsed_file; }; inline std::ostream & operator<<(std::ostream & stream, const ParserParameter & _this) { _this.printself(stream); return stream; } inline std::ostream & operator<<(std::ostream & stream, const ParserSection & section) { section.printself(stream); return stream; } } // akantu namespace std { template <> struct iterator_traits<::akantu::Parser::const_section_iterator> { using iterator_category = input_iterator_tag; using value_type = ::akantu::ParserParameter; using difference_type = ptrdiff_t; using pointer = const ::akantu::ParserParameter *; using reference = const ::akantu::ParserParameter &; }; } #include "parser_tmpl.hh" #endif /* __AKANTU_PARSER_HH__ */ diff --git a/src/io/parser/parser_grammar_tmpl.hh b/src/io/parser/parser_grammar_tmpl.hh index 9174f2529..d957801b7 100644 --- a/src/io/parser/parser_grammar_tmpl.hh +++ b/src/io/parser/parser_grammar_tmpl.hh @@ -1,81 +1,82 @@ /** * @file parser_grammar_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 11 2015 + * @date last modification: Sun Dec 03 2017 * * @brief implementation of the templated part of ParsableParam Parsable and * ParsableParamTyped * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ //#include <boost/config/warning_disable.hpp> #include <boost/spirit/include/classic_position_iterator.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/support_multi_pass.hpp> /* -------------------------------------------------------------------------- */ #ifndef AKANTU_PARSER_GRAMMAR_TMPL_HH #define AKANTU_PARSER_GRAMMAR_TMPL_HH namespace akantu { namespace qi = boost::spirit::qi; /* -------------------------------------------------------------------------- */ template <class T, class Grammar> T Parser::parseType(const std::string & value, Grammar & grammar) { using boost::spirit::ascii::space; std::string::const_iterator b = value.begin(); std::string::const_iterator e = value.end(); T resultat = T(); bool res = false; try { res = qi::phrase_parse(b, e, grammar, space, resultat); } catch (debug::Exception & ex) { AKANTU_EXCEPTION("Could not parse '" << value << "' as a " << debug::demangle(typeid(T).name()) << ", an unknown error append '" << ex.what()); } if (!res || (b != e)) { AKANTU_EXCEPTION("Could not parse '" << value << "' as a " << debug::demangle(typeid(T).name()) << ", an unknown error append '" << std::string(value.begin(), b) << "<HERE>" << std::string(b, e) << "'"); } return resultat; } namespace parser { template <class Iterator> struct Skipper { using type = qi::rule<Iterator, void()>; }; } } // akantu #endif // AKANTU_PARSER_GRAMMAR_TMPL_HH diff --git a/src/io/parser/parser_input_files.cc b/src/io/parser/parser_input_files.cc index 06d388c56..c3016a000 100644 --- a/src/io/parser/parser_input_files.cc +++ b/src/io/parser/parser_input_files.cc @@ -1,119 +1,119 @@ /** * @file parser_input_files.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 11 2015 - * @date last modification: Wed Jan 13 2016 + * @date last modification: Wed Nov 08 2017 * * @brief implementation of the parser * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it - // is only gnu +// is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40600 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "parser_grammar_tmpl.hh" /* -------------------------------------------------------------------------- */ #include "input_file_parser.hh" /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void Parser::parse(const std::string & filename) { this->clean(); std::ifstream input(filename.c_str()); if (!input.good()) { AKANTU_EXCEPTION("Could not open file " << filename << "!"); } input.unsetf(std::ios::skipws); // wrap istream into iterator spirit::istream_iterator fwd_begin(input); spirit::istream_iterator fwd_end; // wrap forward iterator with position iterator, to record the position using pos_iterator_type = spirit::classic::position_iterator2<spirit::istream_iterator>; pos_iterator_type position_begin(fwd_begin, fwd_end, filename); pos_iterator_type position_end; // parse parser::InputFileGrammar<pos_iterator_type> ag(this); bool result = qi::phrase_parse(position_begin, position_end, ag, ag.skipper); if (!result || position_begin != position_end) { spirit::classic::file_position pos = position_begin.get_position(); AKANTU_EXCEPTION("Parse error [ " << ag.getErrorMessage() << " ]" << " in file " << filename << " line " << pos.line << " column " << pos.column << std::endl << "'" << position_begin.get_currentline() << "'" << std::endl << std::setw(pos.column) << " " << "^- here"); } try { bool permissive = getParameter("permissive_parser", _ppsc_current_scope); permissive_parser = permissive; AKANTU_DEBUG_INFO("Parser switched permissive mode to " << std::boolalpha << permissive_parser); } catch (debug::Exception & e) { } last_parsed_file = filename; input.close(); } } // akantu #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it - // is only gnu +// is only gnu #elif defined(__GNUG__) #if GCC_VERSION > 40600 #pragma GCC diagnostic pop #else #pragma GCC diagnostic warning "-Wunused-local-typedefs" #endif #endif diff --git a/src/io/parser/parser_random.cc b/src/io/parser/parser_random.cc index 40b05fe81..46714a06e 100644 --- a/src/io/parser/parser_random.cc +++ b/src/io/parser/parser_random.cc @@ -1,109 +1,109 @@ /** * @file parser_random.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Thu Feb 21 2013 - * @date last modification: Mon Dec 07 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Sun Jul 09 2017 * * @brief implementation of the parser * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it // is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40600 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "parser_grammar_tmpl.hh" /* -------------------------------------------------------------------------- */ #include "algebraic_parser.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ RandomParameter<Real> Parser::parseRandomParameter(const std::string & value, const ParserSection & section) { using boost::spirit::ascii::space_type; parser::RandomGeneratorGrammar<std::string::const_iterator, space_type> grammar(section); grammar.name("random_grammar"); parser::ParsableRandomGenerator rg = Parser::parseType<parser::ParsableRandomGenerator>(value, grammar); Vector<Real> params = rg.parameters; switch (rg.type) { case _rdt_not_defined: return RandomParameter<Real>(rg.base, std::uniform_real_distribution<Real>(0, 0)); case _rdt_uniform: return RandomParameter<Real>( rg.base, std::uniform_real_distribution<Real>(params(0), params(1))); case _rdt_exponential: return RandomParameter<Real>( rg.base, std::exponential_distribution<Real>(params(0))); case _rdt_gamma: return RandomParameter<Real>( rg.base, std::gamma_distribution<Real>(params(0), params(1))); case _rdt_weibull: return RandomParameter<Real>( rg.base, std::weibull_distribution<Real>(params(1), params(0))); case _rdt_extreme_value: return RandomParameter<Real>( rg.base, std::extreme_value_distribution<Real>(params(0), params(1))); case _rdt_normal: return RandomParameter<Real>( rg.base, std::normal_distribution<Real>(params(0), params(1))); case _rdt_lognormal: return RandomParameter<Real>( rg.base, std::lognormal_distribution<Real>(params(0), params(1))); case _rdt_chi_squared: return RandomParameter<Real>( rg.base, std::chi_squared_distribution<Real>(params(0))); case _rdt_cauchy: return RandomParameter<Real>( rg.base, std::cauchy_distribution<Real>(params(0), params(1))); case _rdt_fisher_f: return RandomParameter<Real>( rg.base, std::fisher_f_distribution<Real>(params(0), params(1))); case _rdt_student_t: return RandomParameter<Real>(rg.base, std::student_t_distribution<Real>(params(0))); default: AKANTU_EXCEPTION("This is an unknown random distribution in the parser"); } } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/io/parser/parser_real.cc b/src/io/parser/parser_real.cc index 423307831..0c8471c13 100644 --- a/src/io/parser/parser_real.cc +++ b/src/io/parser/parser_real.cc @@ -1,63 +1,63 @@ /** * @file parser_real.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Thu Feb 21 2013 - * @date last modification: Wed Nov 11 2015 + * @date creation: Mon Dec 13 2010 + * @date last modification: Mon Jun 19 2017 * * @brief implementation of the parser * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it - // is only gnu +// is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40600 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "parser_grammar_tmpl.hh" /* -------------------------------------------------------------------------- */ #include "algebraic_parser.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Real Parser::parseReal(const std::string & value, const ParserSection & section) { using boost::spirit::ascii::space_type; parser::AlgebraicGrammar<std::string::const_iterator, space_type> grammar( section); grammar.name("algebraic_grammar"); return Parser::parseType<Real>(value, grammar); } } // akantu diff --git a/src/io/parser/parser_tmpl.hh b/src/io/parser/parser_tmpl.hh index c65c8d82c..f3ba422c9 100644 --- a/src/io/parser/parser_tmpl.hh +++ b/src/io/parser/parser_tmpl.hh @@ -1,111 +1,112 @@ /** * @file parser_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Wed Apr 22 2015 + * @date last modification: Mon Dec 18 2017 * * @brief Implementation of the parser templated methods * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include <regex> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> inline ParserParameter::operator T() const { T t; std::stringstream sstr(value); sstr >> t; if (sstr.bad()) AKANTU_EXCEPTION("No known conversion of a ParserParameter \"" << name << "\" to the type " << typeid(T).name()); return t; } /* -------------------------------------------------------------------------- */ template <> inline ParserParameter::operator const char *() const { return value.c_str(); } /* -------------------------------------------------------------------------- */ template <> inline ParserParameter::operator Real() const { return Parser::parseReal(value, *parent_section); } /* --------------------------------------------------------- ----------------- */ template <> inline ParserParameter::operator bool() const { bool b; std::stringstream sstr(value); sstr >> std::boolalpha >> b; if (sstr.fail()) { sstr.clear(); sstr >> std::noboolalpha >> b; } return b; } /* -------------------------------------------------------------------------- */ template <> inline ParserParameter::operator std::vector<std::string>() const { std::vector<std::string> tmp; auto string = std::regex_replace(value, std::regex("[[:space:]]|\\[|\\]"), ""); std::smatch sm; while (std::regex_search(string, sm, std::regex("[^,]+"))) { tmp.push_back(sm.str()); string = sm.suffix(); } return tmp; } /* --------------------------------------------------------- ----------------- */ template <> inline ParserParameter::operator Vector<Real>() const { return Parser::parseVector(value, *parent_section); } /* --------------------------------------------------------- ----------------- */ template <> inline ParserParameter::operator Vector<UInt>() const { Vector<Real> tmp = Parser::parseVector(value, *parent_section); Vector<UInt> tmp_uint(tmp.size()); for (UInt i = 0; i < tmp.size(); ++i) { tmp_uint(i) = UInt(tmp(i)); } return tmp_uint; } /* --------------------------------------------------------- ----------------- */ template <> inline ParserParameter::operator Matrix<Real>() const { return Parser::parseMatrix(value, *parent_section); } /* -------------------------------------------------------------------------- */ template <> inline ParserParameter::operator RandomParameter<Real>() const { return Parser::parseRandomParameter(value, *parent_section); } } // akantu diff --git a/src/io/parser/parser_types.cc b/src/io/parser/parser_types.cc index 34bde6424..2b60bfdbd 100644 --- a/src/io/parser/parser_types.cc +++ b/src/io/parser/parser_types.cc @@ -1,75 +1,75 @@ /** * @file parser_types.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Thu Feb 21 2013 - * @date last modification: Wed Nov 11 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Mon Jun 19 2017 * * @brief implementation of the parser * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it - // is only gnu +// is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40600 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "parser_grammar_tmpl.hh" /* -------------------------------------------------------------------------- */ #include "algebraic_parser.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Vector<Real> Parser::parseVector(const std::string & value, const ParserSection & section) { using boost::spirit::ascii::space_type; parser::VectorGrammar<std::string::const_iterator, space_type> grammar( section); grammar.name("vector_grammar"); return Parser::parseType<parser::parsable_vector>(value, grammar); } /* -------------------------------------------------------------------------- */ Matrix<Real> Parser::parseMatrix(const std::string & value, const ParserSection & section) { using boost::spirit::ascii::space_type; parser::MatrixGrammar<std::string::const_iterator, space_type> grammar( section); grammar.name("matrix_grammar"); return Parser::parseType<parser::parsable_matrix>(value, grammar); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/mesh/element_group.cc b/src/mesh/element_group.cc index 9f0158d7a..ded48bb53 100644 --- a/src/mesh/element_group.cc +++ b/src/mesh/element_group.cc @@ -1,203 +1,203 @@ /** * @file element_group.cc * * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Mon Jan 22 2018 * * @brief Stores information relevent to the notion of domain boundary and * surfaces. * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_csr.hh" #include "dumpable.hh" #include "dumpable_inline_impl.hh" #include "group_manager.hh" #include "group_manager_inline_impl.cc" #include "mesh.hh" #include "mesh_utils.hh" #include <algorithm> #include <iterator> #include <sstream> #include "element_group.hh" #if defined(AKANTU_USE_IOHELPER) #include "dumper_iohelper_paraview.hh" #endif namespace akantu { /* -------------------------------------------------------------------------- */ ElementGroup::ElementGroup(const std::string & group_name, const Mesh & mesh, NodeGroup & node_group, UInt dimension, const std::string & id, const MemoryID & mem_id) : Memory(id, mem_id), mesh(mesh), name(group_name), elements("elements", id, mem_id), node_group(node_group), dimension(dimension) { AKANTU_DEBUG_IN(); #if defined(AKANTU_USE_IOHELPER) this->registerDumper<DumperParaview>("paraview_" + group_name, group_name, true); this->addDumpFilteredMesh(mesh, elements, node_group.getNodes(), dimension); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementGroup::empty() { elements.free(); } /* -------------------------------------------------------------------------- */ void ElementGroup::append(const ElementGroup & other_group) { AKANTU_DEBUG_IN(); node_group.append(other_group.node_group); /// loop on all element types in all dimensions for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; type_iterator it = other_group.firstType(_all_dimensions, ghost_type, _ek_not_defined); type_iterator last = other_group.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != last; ++it) { ElementType type = *it; const Array<UInt> & other_elem_list = other_group.elements(type, ghost_type); UInt nb_other_elem = other_elem_list.size(); Array<UInt> * elem_list; UInt nb_elem = 0; /// create current type if doesn't exists, otherwise get information if (elements.exists(type, ghost_type)) { elem_list = &elements(type, ghost_type); nb_elem = elem_list->size(); } else { elem_list = &(elements.alloc(0, 1, type, ghost_type)); } /// append new elements to current list elem_list->resize(nb_elem + nb_other_elem); std::copy(other_elem_list.begin(), other_elem_list.end(), elem_list->begin() + nb_elem); /// remove duplicates std::sort(elem_list->begin(), elem_list->end()); Array<UInt>::iterator<> end = std::unique(elem_list->begin(), elem_list->end()); elem_list->resize(end - elem_list->begin()); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementGroup::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ElementGroup [" << std::endl; stream << space << " + name: " << name << std::endl; stream << space << " + dimension: " << dimension << std::endl; elements.printself(stream, indent + 1); node_group.printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void ElementGroup::optimize() { // increasing the locality of data when iterating on the element of a group for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; ElementList::type_iterator it = elements.firstType(_all_dimensions, ghost_type); ElementList::type_iterator last = elements.lastType(_all_dimensions, ghost_type); for (; it != last; ++it) { Array<UInt> & els = elements(*it, ghost_type); std::sort(els.begin(), els.end()); Array<UInt>::iterator<> end = std::unique(els.begin(), els.end()); els.resize(end - els.begin()); } } node_group.optimize(); } /* -------------------------------------------------------------------------- */ void ElementGroup::fillFromNodeGroup() { CSR<Element> node_to_elem; MeshUtils::buildNode2Elements(this->mesh, node_to_elem, this->dimension); std::set<Element> seen; Array<UInt>::const_iterator<> itn = this->node_group.begin(); Array<UInt>::const_iterator<> endn = this->node_group.end(); for (; itn != endn; ++itn) { CSR<Element>::iterator ite = node_to_elem.begin(*itn); CSR<Element>::iterator ende = node_to_elem.end(*itn); for (; ite != ende; ++ite) { const Element & elem = *ite; if (this->dimension != _all_dimensions && this->dimension != Mesh::getSpatialDimension(elem.type)) continue; if (seen.find(elem) != seen.end()) continue; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(elem.type); Array<UInt>::const_iterator<Vector<UInt>> conn_it = this->mesh.getConnectivity(elem.type, elem.ghost_type) .begin(nb_nodes_per_element); const Vector<UInt> & conn = conn_it[elem.element]; UInt count = 0; for (UInt n = 0; n < conn.size(); ++n) { count += (this->node_group.getNodes().find(conn(n)) != UInt(-1) ? 1 : 0); } if (count == nb_nodes_per_element) this->add(elem); seen.insert(elem); } } this->optimize(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/mesh/element_group.hh b/src/mesh/element_group.hh index fe47dc7d2..64615adaf 100644 --- a/src/mesh/element_group.hh +++ b/src/mesh/element_group.hh @@ -1,190 +1,190 @@ /** * @file element_group.hh * * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri May 03 2013 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Stores information relevent to the notion of domain boundary and * surfaces. * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "dumpable.hh" #include "element_type_map.hh" #include "node_group.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_GROUP_HH__ #define __AKANTU_ELEMENT_GROUP_HH__ namespace akantu { class Mesh; class Element; } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ class ElementGroup : private Memory, public Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ElementGroup(const std::string & name, const Mesh & mesh, NodeGroup & node_group, UInt dimension = _all_dimensions, const std::string & id = "element_group", const MemoryID & memory_id = 0); /* ------------------------------------------------------------------------ */ /* Type definitions */ /* ------------------------------------------------------------------------ */ public: using ElementList = ElementTypeMapArray<UInt>; using NodeList = Array<UInt>; /* ------------------------------------------------------------------------ */ /* Element iterator */ /* ------------------------------------------------------------------------ */ using type_iterator = ElementList::type_iterator; inline type_iterator firstType(UInt dim = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & kind = _ek_regular) const; inline type_iterator lastType(UInt dim = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & kind = _ek_regular) const; #ifndef SWIG template <typename... pack> inline decltype(auto) elementTypes(pack &&... _pack) const { return elements.elementTypes(_pack...); } #endif using const_element_iterator = Array<UInt>::const_iterator<UInt>; inline const_element_iterator begin(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; inline const_element_iterator end(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// empty the element group void empty(); /// append another group to this group /// BE CAREFUL: it doesn't conserve the element order void append(const ElementGroup & other_group); /// add an element to the group. By default the it does not add the nodes to /// the group inline void add(const Element & el, bool add_nodes = false, bool check_for_duplicate = true); /// \todo fix the default for add_nodes : make it coherent with the other /// method inline void add(const ElementType & type, UInt element, const GhostType & ghost_type = _not_ghost, bool add_nodes = true, bool check_for_duplicate = true); inline void addNode(UInt node_id, bool check_for_duplicate = true); inline void removeNode(UInt node_id); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// fill the elements based on the underlying node group. virtual void fillFromNodeGroup(); // sort and remove duplicated values void optimize(); private: inline void addElement(const ElementType & elem_type, UInt elem_id, const GhostType & ghost_type); friend class GroupManager; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: const Array<UInt> & getElements(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; AKANTU_GET_MACRO(Elements, elements, const ElementTypeMapArray<UInt> &); AKANTU_GET_MACRO(Nodes, node_group.getNodes(), const Array<UInt> &); AKANTU_GET_MACRO(NodeGroup, node_group, const NodeGroup &); AKANTU_GET_MACRO_NOT_CONST(NodeGroup, node_group, NodeGroup &); AKANTU_GET_MACRO(Dimension, dimension, UInt); AKANTU_GET_MACRO(Name, name, std::string); inline UInt getNbNodes() const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// Mesh to which this group belongs const Mesh & mesh; /// name of the group std::string name; /// list of elements composing the group ElementList elements; /// sub list of nodes which are composing the elements NodeGroup & node_group; /// group dimension UInt dimension; /// empty arry for the iterator to work when an element type not present Array<UInt> empty_elements; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const ElementGroup & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "element.hh" #include "element_group_inline_impl.cc" #endif /* __AKANTU_ELEMENT_GROUP_HH__ */ diff --git a/src/mesh/element_group_inline_impl.cc b/src/mesh/element_group_inline_impl.cc index bd084f56c..7ae8b3750 100644 --- a/src/mesh/element_group_inline_impl.cc +++ b/src/mesh/element_group_inline_impl.cc @@ -1,146 +1,146 @@ /** * @file element_group_inline_impl.cc * * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Sun Aug 13 2017 * - * @brief Stores information relevent to the notion of domain boundary and + * @brief Stores information relevent to the notion of domain boundary and * surfaces. * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_group.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_GROUP_INLINE_IMPL_CC__ #define __AKANTU_ELEMENT_GROUP_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline void ElementGroup::add(const Element & el, bool add_nodes, bool check_for_duplicate) { this->add(el.type, el.element, el.ghost_type, add_nodes, check_for_duplicate); } /* -------------------------------------------------------------------------- */ inline void ElementGroup::add(const ElementType & type, UInt element, const GhostType & ghost_type, bool add_nodes, bool check_for_duplicate) { addElement(type, element, ghost_type); if (add_nodes) { Array<UInt>::const_vector_iterator it = mesh.getConnectivity(type, ghost_type) .begin(mesh.getNbNodesPerElement(type)) + element; const Vector<UInt> & conn = *it; for (UInt i = 0; i < conn.size(); ++i) addNode(conn[i], check_for_duplicate); } } /* -------------------------------------------------------------------------- */ inline void ElementGroup::addNode(UInt node_id, bool check_for_duplicate) { node_group.add(node_id, check_for_duplicate); } /* -------------------------------------------------------------------------- */ inline void ElementGroup::removeNode(UInt node_id) { node_group.remove(node_id); } /* -------------------------------------------------------------------------- */ inline void ElementGroup::addElement(const ElementType & elem_type, UInt elem_id, const GhostType & ghost_type) { if (!(elements.exists(elem_type, ghost_type))) { elements.alloc(0, 1, elem_type, ghost_type); } elements(elem_type, ghost_type).push_back(elem_id); this->dimension = UInt( std::max(Int(this->dimension), Int(mesh.getSpatialDimension(elem_type)))); } /* -------------------------------------------------------------------------- */ inline UInt ElementGroup::getNbNodes() const { return node_group.size(); } /* -------------------------------------------------------------------------- */ inline ElementGroup::type_iterator ElementGroup::firstType(UInt dim, const GhostType & ghost_type, const ElementKind & kind) const { return elements.firstType(dim, ghost_type, kind); } /* -------------------------------------------------------------------------- */ inline ElementGroup::type_iterator ElementGroup::lastType(UInt dim, const GhostType & ghost_type, const ElementKind & kind) const { return elements.lastType(dim, ghost_type, kind); } /* -------------------------------------------------------------------------- */ inline ElementGroup::const_element_iterator ElementGroup::begin(const ElementType & type, const GhostType & ghost_type) const { if (elements.exists(type, ghost_type)) { return elements(type, ghost_type).begin(); } else { return empty_elements.begin(); } } /* -------------------------------------------------------------------------- */ inline ElementGroup::const_element_iterator ElementGroup::end(const ElementType & type, const GhostType & ghost_type) const { if (elements.exists(type, ghost_type)) { return elements(type, ghost_type).end(); } else { return empty_elements.end(); } } /* -------------------------------------------------------------------------- */ inline const Array<UInt> & ElementGroup::getElements(const ElementType & type, const GhostType & ghost_type) const { if (elements.exists(type, ghost_type)) { return elements(type, ghost_type); } else { return empty_elements; } } /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_ELEMENT_GROUP_INLINE_IMPL_CC__ */ diff --git a/src/mesh/element_type_map.cc b/src/mesh/element_type_map.cc index ee0fc8cca..83fccc3a9 100644 --- a/src/mesh/element_type_map.cc +++ b/src/mesh/element_type_map.cc @@ -1,71 +1,73 @@ /** * @file element_type_map.cc * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Tue Jun 27 2017 + * @date creation: Fri Jun 18 2010 + * @date last modification: Tue Feb 20 2018 * - * @brief A Documented file. + * @brief A Documented file. * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer( const FEEngine & fe_engine, UInt nb_component, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) : MeshElementTypeMapArrayInitializer( fe_engine.getMesh(), nb_component, spatial_dimension == UInt(-2) ? fe_engine.getMesh().getSpatialDimension() : spatial_dimension, ghost_type, element_kind, true, false), fe_engine(fe_engine) {} FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer( const FEEngine & fe_engine, const ElementTypeMapArrayInitializer::CompFunc & nb_component, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) : MeshElementTypeMapArrayInitializer( fe_engine.getMesh(), nb_component, spatial_dimension == UInt(-2) ? fe_engine.getMesh().getSpatialDimension() : spatial_dimension, ghost_type, element_kind, true, false), fe_engine(fe_engine) {} UInt FEEngineElementTypeMapArrayInitializer::size( const ElementType & type) const { return MeshElementTypeMapArrayInitializer::size(type) * fe_engine.getNbIntegrationPoints(type, this->ghost_type); } FEEngineElementTypeMapArrayInitializer::ElementTypesIteratorHelper FEEngineElementTypeMapArrayInitializer::elementTypes() const { return this->fe_engine.elementTypes(spatial_dimension, ghost_type, element_kind); } } // namespace akantu diff --git a/src/mesh/element_type_map.hh b/src/mesh/element_type_map.hh index f3aefd368..4853569a7 100644 --- a/src/mesh/element_type_map.hh +++ b/src/mesh/element_type_map.hh @@ -1,449 +1,449 @@ /** * @file element_type_map.hh * + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 31 2011 - * @date last modification: Fri Oct 02 2015 + * @date last modification: Tue Feb 20 2018 * * @brief storage class by element type * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_memory.hh" #include "aka_named_argument.hh" #include "element.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_TYPE_MAP_HH__ #define __AKANTU_ELEMENT_TYPE_MAP_HH__ namespace akantu { class FEEngine; } // namespace akantu namespace akantu { namespace { DECLARE_NAMED_ARGUMENT(all_ghost_types); DECLARE_NAMED_ARGUMENT(default_value); DECLARE_NAMED_ARGUMENT(element_kind); DECLARE_NAMED_ARGUMENT(ghost_type); DECLARE_NAMED_ARGUMENT(nb_component); DECLARE_NAMED_ARGUMENT(nb_component_functor); DECLARE_NAMED_ARGUMENT(with_nb_element); DECLARE_NAMED_ARGUMENT(with_nb_nodes_per_element); DECLARE_NAMED_ARGUMENT(spatial_dimension); DECLARE_NAMED_ARGUMENT(do_not_default); } // namespace template <class Stored, typename SupportType = ElementType> class ElementTypeMap; /* -------------------------------------------------------------------------- */ /* ElementTypeMapBase */ /* -------------------------------------------------------------------------- */ /// Common non templated base class for the ElementTypeMap class class ElementTypeMapBase { public: virtual ~ElementTypeMapBase() = default; }; /* -------------------------------------------------------------------------- */ /* ElementTypeMap */ /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> class ElementTypeMap : public ElementTypeMapBase { public: ElementTypeMap(); ~ElementTypeMap() override; inline static std::string printType(const SupportType & type, const GhostType & ghost_type); /*! Tests whether a type is present in the object * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return true if the type is present. */ inline bool exists(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /*! get the stored data corresponding to a type * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ inline const Stored & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /*! get the stored data corresponding to a type * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ inline Stored & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost); /*! insert data of a new type (not yet present) into the map. THIS METHOD IS * NOT ARRAY SAFE, when using ElementTypeMapArray, use setArray instead * @param data to insert * @param type type of data (if this type is already present in the map, * an exception is thrown). * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ template <typename U> inline Stored & operator()(U && insertee, const SupportType & type, const GhostType & ghost_type = _not_ghost); public: /// print helper virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ /*! iterator allows to iterate over type-data pairs of the map. The interface * expects the SupportType to be ElementType. */ using DataMap = std::map<SupportType, Stored>; class type_iterator : private std::iterator<std::forward_iterator_tag, const SupportType> { public: using value_type = const SupportType; using pointer = const SupportType *; using reference = const SupportType &; protected: using DataMapIterator = typename ElementTypeMap<Stored>::DataMap::const_iterator; public: type_iterator(DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek); type_iterator(const type_iterator & it); type_iterator() = default; inline reference operator*(); inline reference operator*() const; inline type_iterator & operator++(); type_iterator operator++(int); inline bool operator==(const type_iterator & other) const; inline bool operator!=(const type_iterator & other) const; type_iterator & operator=(const type_iterator & other); private: DataMapIterator list_begin; DataMapIterator list_end; UInt dim; ElementKind kind; }; /// helper class to use in range for constructions class ElementTypesIteratorHelper { public: using Container = ElementTypeMap<Stored, SupportType>; using iterator = typename Container::type_iterator; ElementTypesIteratorHelper(const Container & container, UInt dim, GhostType ghost_type, ElementKind kind) : container(std::cref(container)), dim(dim), ghost_type(ghost_type), kind(kind) {} template <typename... pack> ElementTypesIteratorHelper(const Container & container, use_named_args_t, pack &&... _pack) : ElementTypesIteratorHelper( container, OPTIONAL_NAMED_ARG(spatial_dimension, _all_dimensions), OPTIONAL_NAMED_ARG(ghost_type, _not_ghost), OPTIONAL_NAMED_ARG(element_kind, _ek_regular)) {} ElementTypesIteratorHelper(const ElementTypesIteratorHelper &) = default; ElementTypesIteratorHelper & operator=(const ElementTypesIteratorHelper &) = default; ElementTypesIteratorHelper & operator=(ElementTypesIteratorHelper &&) = default; iterator begin() { return container.get().firstType(dim, ghost_type, kind); } iterator end() { return container.get().lastType(dim, ghost_type, kind); } private: std::reference_wrapper<const Container> container; UInt dim; GhostType ghost_type; ElementKind kind; }; private: ElementTypesIteratorHelper elementTypesImpl(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const; template <typename... pack> ElementTypesIteratorHelper elementTypesImpl(const use_named_args_t & /*unused*/, pack &&... _pack) const; public: /*! * \param _spatial_dimension optional: filter for elements of given spatial * dimension * \param _ghost_type optional: filter for a certain ghost_type * \param _element_kind optional: filter for elements of given kind */ template <typename... pack> std::enable_if_t<are_named_argument<pack...>::value, ElementTypesIteratorHelper> elementTypes(pack &&... _pack) const { return elementTypesImpl(use_named_args, std::forward<decltype(_pack)>(_pack)...); } template <typename... pack> std::enable_if_t<not are_named_argument<pack...>::value, ElementTypesIteratorHelper> elementTypes(pack &&... _pack) const { return elementTypesImpl(std::forward<decltype(_pack)>(_pack)...); } public: /*! Get an iterator to the beginning of a subset datamap. This method expects * the SupportType to be ElementType. * @param dim optional: iterate over data of dimension dim (e.g. when * iterating over (surface) facets of a 3D mesh, dim would be 2). * by default, all dimensions are considered. * @param ghost_type optional: by default, the data map for non-ghost * elements is iterated over. * @param kind optional: the kind of element to search for (see * aka_common.hh), by default all kinds are considered * @return an iterator to the first stored data matching the filters * or an iterator to the end of the map if none match*/ inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; /*! Get an iterator to the end of a subset datamap. This method expects * the SupportType to be ElementType. * @param dim optional: iterate over data of dimension dim (e.g. when * iterating over (surface) facets of a 3D mesh, dim would be 2). * by default, all dimensions are considered. * @param ghost_type optional: by default, the data map for non-ghost * elements is iterated over. * @param kind optional: the kind of element to search for (see * aka_common.hh), by default all kinds are considered * @return an iterator to the last stored data matching the filters * or an iterator to the end of the map if none match */ inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; protected: /*! Direct access to the underlying data map. for internal use by daughter * classes only * @param ghost_type whether to return the data map or the ghost_data map * @return the raw map */ inline DataMap & getData(GhostType ghost_type); /*! Direct access to the underlying data map. for internal use by daughter * classes only * @param ghost_type whether to return the data map or the ghost_data map * @return the raw map */ inline const DataMap & getData(GhostType ghost_type) const; /* ------------------------------------------------------------------------ */ protected: DataMap data; DataMap ghost_data; }; /* -------------------------------------------------------------------------- */ /* Some typedefs */ /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> class ElementTypeMapArray : public ElementTypeMap<Array<T> *, SupportType>, public Memory { public: using type = T; using array_type = Array<T>; protected: using parent = ElementTypeMap<Array<T> *, SupportType>; using DataMap = typename parent::DataMap; public: using type_iterator = typename parent::type_iterator; /// standard assigment (copy) operator void operator=(const ElementTypeMapArray &) = delete; ElementTypeMapArray(const ElementTypeMapArray &) = delete; /// explicit copy void copy(const ElementTypeMapArray & other); /*! Constructor * @param id optional: identifier (string) * @param parent_id optional: parent identifier. for organizational purposes * only * @param memory_id optional: choose a specific memory, defaults to memory 0 */ ElementTypeMapArray(const ID & id = "by_element_type_array", const ID & parent_id = "no_parent", const MemoryID & memory_id = 0) : parent(), Memory(parent_id + ":" + id, memory_id), name(id){}; /*! allocate memory for a new array * @param size number of tuples of the new array * @param nb_component tuple size * @param type the type under which the array is indexed in the map * @param ghost_type whether to add the field to the data map or the * ghost_data map * @return a reference to the allocated array */ inline Array<T> & alloc(UInt size, UInt nb_component, const SupportType & type, const GhostType & ghost_type, const T & default_value = T()); /*! allocate memory for a new array in both the data and the ghost_data map * @param size number of tuples of the new array * @param nb_component tuple size * @param type the type under which the array is indexed in the map*/ inline void alloc(UInt size, UInt nb_component, const SupportType & type, const T & default_value = T()); /* get a reference to the array of certain type * @param type data filed under type is returned * @param ghost_type optional: by default the non-ghost map is searched * @return a reference to the array */ inline const Array<T> & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /// access the data of an element, this combine the map and array accessor inline const T & operator()(const Element & element, UInt component = 0) const; /// access the data of an element, this combine the map and array accessor inline T & operator()(const Element & element, UInt component = 0); /* get a reference to the array of certain type * @param type data filed under type is returned * @param ghost_type optional: by default the non-ghost map is searched * @return a const reference to the array */ inline Array<T> & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost); /*! insert data of a new type (not yet present) into the map. * @param type type of data (if this type is already present in the map, * an exception is thrown). * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @param vect the vector to include into the map * @return stored data corresponding to type. */ inline void setArray(const SupportType & type, const GhostType & ghost_type, const Array<T> & vect); /*! frees all memory related to the data*/ inline void free(); /*! set all values in the ElementTypeMap to zero*/ inline void clear(); /*! set all values in the ElementTypeMap to value */ template <typename ST> inline void set(const ST & value); /*! deletes and reorders entries in the stored arrays * @param new_numbering a ElementTypeMapArray of new indices. UInt(-1) * indicates * deleted entries. */ inline void onElementsRemoved(const ElementTypeMapArray<UInt> & new_numbering); /// text output helper void printself(std::ostream & stream, int indent = 0) const override; /*! set the id * @param id the new name */ inline void setID(const ID & id) { this->id = id; } ElementTypeMap<UInt> getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const { ElementTypeMap<UInt> nb_components; for (auto & type : this->elementTypes(dim, ghost_type, kind)) { UInt nb_comp = (*this)(type, ghost_type).getNbComponent(); nb_components(type, ghost_type) = nb_comp; } return nb_components; } /* ------------------------------------------------------------------------ */ /* more evolved allocators */ /* ------------------------------------------------------------------------ */ public: /// initialize the arrays in accordance to a functor template <class Func> void initialize(const Func & f, const T & default_value, bool do_not_default); /// initialize with sizes and number of components in accordance of a mesh /// content template <typename... pack> void initialize(const Mesh & mesh, pack &&... _pack); /// initialize with sizes and number of components in accordance of a fe /// engine content (aka integration points) template <typename... pack> void initialize(const FEEngine & fe_engine, pack &&... _pack); /* ------------------------------------------------------------------------ */ /* Accesssors */ /* ------------------------------------------------------------------------ */ public: /// get the name of the internal field AKANTU_GET_MACRO(Name, name, ID); /// name of the elment type map: e.g. connectivity, grad_u ID name; }; /// to store data Array<Real> by element type using ElementTypeMapReal = ElementTypeMapArray<Real>; /// to store data Array<Int> by element type using ElementTypeMapInt = ElementTypeMapArray<Int>; /// to store data Array<UInt> by element type using ElementTypeMapUInt = ElementTypeMapArray<UInt, ElementType>; /// Map of data of type UInt stored in a mesh using UIntDataMap = std::map<std::string, Array<UInt> *>; using ElementTypeMapUIntDataMap = ElementTypeMap<UIntDataMap, ElementType>; } // namespace akantu #endif /* __AKANTU_ELEMENT_TYPE_MAP_HH__ */ diff --git a/src/mesh/element_type_map_filter.hh b/src/mesh/element_type_map_filter.hh index 81c6ab58b..834469672 100644 --- a/src/mesh/element_type_map_filter.hh +++ b/src/mesh/element_type_map_filter.hh @@ -1,307 +1,307 @@ /** * @file element_type_map_filter.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 - * @date last modification: Fri Dec 18 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Filtered version based on a an akantu::ElementGroup of a * akantu::ElementTypeMap * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_BY_ELEMENT_TYPE_FILTER_HH__ #define __AKANTU_BY_ELEMENT_TYPE_FILTER_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* ArrayFilter */ /* -------------------------------------------------------------------------- */ template <typename T> class ArrayFilter { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: /// standard iterator template <typename R = T> class iterator { inline bool operator!=(__attribute__((unused)) iterator<R> & other) { throw; }; inline bool operator==(__attribute__((unused)) iterator<R> & other) { throw; }; inline iterator<R> & operator++() { throw; }; inline T operator*() { throw; return T(); }; }; /// const iterator template <template <class S> class original_iterator, typename Shape, typename filter_iterator> class const_iterator { public: UInt getCurrentIndex() { return (*this->filter_it * this->nb_item_per_elem + this->sub_element_counter); } inline const_iterator() = default; inline const_iterator(const original_iterator<Shape> & origin_it, const filter_iterator & filter_it, UInt nb_item_per_elem) : origin_it(origin_it), filter_it(filter_it), nb_item_per_elem(nb_item_per_elem), sub_element_counter(0){}; inline bool operator!=(const_iterator & other) const { return !((*this) == other); } inline bool operator==(const_iterator & other) const { return (this->origin_it == other.origin_it && this->filter_it == other.filter_it && this->sub_element_counter == other.sub_element_counter); } inline bool operator!=(const const_iterator & other) const { return !((*this) == other); } inline bool operator==(const const_iterator & other) const { return (this->origin_it == other.origin_it && this->filter_it == other.filter_it && this->sub_element_counter == other.sub_element_counter); } inline const_iterator & operator++() { ++sub_element_counter; if (sub_element_counter == nb_item_per_elem) { sub_element_counter = 0; ++filter_it; } return *this; }; inline Shape operator*() { return origin_it[nb_item_per_elem * (*filter_it) + sub_element_counter]; }; private: original_iterator<Shape> origin_it; filter_iterator filter_it; /// the number of item per element UInt nb_item_per_elem; /// counter for every sub element group UInt sub_element_counter; }; using vector_iterator = iterator<Vector<T>>; using array_type = Array<T>; using const_vector_iterator = const_iterator<array_type::template const_iterator, Vector<T>, Array<UInt>::const_iterator<UInt>>; using value_type = typename array_type::value_type; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ArrayFilter(const Array<T> & array, const Array<UInt> & filter, UInt nb_item_per_elem) : array(array), filter(filter), nb_item_per_elem(nb_item_per_elem){}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ const_vector_iterator begin_reinterpret(UInt n, UInt new_size) const { AKANTU_DEBUG_ASSERT( n * new_size == this->getNbComponent() * this->size(), "The new values for size (" << new_size << ") and nb_component (" << n << ") are not compatible with the one of this array(" << this->size() << "," << this->getNbComponent() << ")"); UInt new_full_array_size = this->array.size() * array.getNbComponent() / n; UInt new_nb_item_per_elem = this->nb_item_per_elem; if (new_size != 0 && n != 0) new_nb_item_per_elem = this->array.getNbComponent() * this->filter.size() * this->nb_item_per_elem / (n * new_size); return const_vector_iterator( this->array.begin_reinterpret(n, new_full_array_size), this->filter.begin(), new_nb_item_per_elem); }; const_vector_iterator end_reinterpret(UInt n, UInt new_size) const { AKANTU_DEBUG_ASSERT( n * new_size == this->getNbComponent() * this->size(), "The new values for size (" << new_size << ") and nb_component (" << n << ") are not compatible with the one of this array(" << this->size() << "," << this->getNbComponent() << ")"); UInt new_full_array_size = this->array.size() * this->array.getNbComponent() / n; UInt new_nb_item_per_elem = this->nb_item_per_elem; if (new_size != 0 && n != 0) new_nb_item_per_elem = this->array.getNbComponent() * this->filter.size() * this->nb_item_per_elem / (n * new_size); return const_vector_iterator( this->array.begin_reinterpret(n, new_full_array_size), this->filter.end(), new_nb_item_per_elem); }; vector_iterator begin_reinterpret(UInt, UInt) { throw; }; vector_iterator end_reinterpret(UInt, UInt) { throw; }; /// return the size of the filtered array which is the filter size UInt size() const { return this->filter.size() * this->nb_item_per_elem; }; /// the number of components of the filtered array UInt getNbComponent() const { return this->array.getNbComponent(); }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// reference to array of data const Array<T> & array; /// reference to the filter used to select elements const Array<UInt> & filter; /// the number of item per element UInt nb_item_per_elem; }; /* -------------------------------------------------------------------------- */ /* ElementTypeMapFilter */ /* -------------------------------------------------------------------------- */ template <class T, typename SupportType = ElementType> class ElementTypeMapArrayFilter { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: using type = T; using array_type = ArrayFilter<T>; using value_type = typename array_type::value_type; using type_iterator = typename ElementTypeMapArray<UInt, SupportType>::type_iterator; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ElementTypeMapArrayFilter( const ElementTypeMapArray<T, SupportType> & array, const ElementTypeMapArray<UInt, SupportType> & filter, const ElementTypeMap<UInt, SupportType> & nb_data_per_elem) : array(array), filter(filter), nb_data_per_elem(nb_data_per_elem) {} ElementTypeMapArrayFilter( const ElementTypeMapArray<T, SupportType> & array, const ElementTypeMapArray<UInt, SupportType> & filter) : array(array), filter(filter) {} ~ElementTypeMapArrayFilter() = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ inline const ArrayFilter<T> operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost) const { if (filter.exists(type, ghost_type)) { if (nb_data_per_elem.exists(type, ghost_type)) return ArrayFilter<T>(array(type, ghost_type), filter(type, ghost_type), nb_data_per_elem(type, ghost_type) / array(type, ghost_type).getNbComponent()); else return ArrayFilter<T>(array(type, ghost_type), filter(type, ghost_type), 1); } else { return ArrayFilter<T>(empty_array, empty_filter, 1); } }; inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const { return filter.firstType(dim, ghost_type, kind); }; inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const { return filter.lastType(dim, ghost_type, kind); }; ElementTypeMap<UInt> getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const { return this->array.getNbComponents(dim, ghost_type, kind); }; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ std::string getID() { return std::string("filtered:" + this->array().getID()); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: const ElementTypeMapArray<T, SupportType> & array; const ElementTypeMapArray<UInt, SupportType> & filter; ElementTypeMap<UInt> nb_data_per_elem; /// Empty array to be able to return consistent filtered arrays Array<T> empty_array; Array<UInt> empty_filter; }; } // namespace akantu #endif /* __AKANTU_BY_ELEMENT_TYPE_FILTER_HH__ */ diff --git a/src/mesh/element_type_map_tmpl.hh b/src/mesh/element_type_map_tmpl.hh index 6793158a1..2afd4aa37 100644 --- a/src/mesh/element_type_map_tmpl.hh +++ b/src/mesh/element_type_map_tmpl.hh @@ -1,747 +1,747 @@ /** * @file element_type_map_tmpl.hh * + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 31 2011 - * @date last modification: Fri Oct 02 2015 + * @date last modification: Tue Feb 20 2018 * * @brief implementation of template functions of the ElementTypeMap and * ElementTypeMapArray classes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_static_if.hh" #include "element_type_map.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include "element_type_conversion.hh" /* -------------------------------------------------------------------------- */ #include <functional> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ #define __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* ElementTypeMap */ /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline std::string ElementTypeMap<Stored, SupportType>::printType(const SupportType & type, const GhostType & ghost_type) { std::stringstream sstr; sstr << "(" << ghost_type << ":" << type << ")"; return sstr.str(); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline bool ElementTypeMap<Stored, SupportType>::exists( const SupportType & type, const GhostType & ghost_type) const { return this->getData(ghost_type).find(type) != this->getData(ghost_type).end(); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline const Stored & ElementTypeMap<Stored, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) const { auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMap::printType(type, ghost_type) << " in this ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> class"); return it->second; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline Stored & ElementTypeMap<Stored, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) { return this->getData(ghost_type)[type]; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> template <typename U> inline Stored & ElementTypeMap<Stored, SupportType>:: operator()(U && insertee, const SupportType & type, const GhostType & ghost_type) { auto it = this->getData(ghost_type).find(type); if (it != this->getData(ghost_type).end()) { AKANTU_SILENT_EXCEPTION("Element of type " << ElementTypeMap::printType(type, ghost_type) << " already in this ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> class"); } else { auto & data = this->getData(ghost_type); const auto & res = data.insert(std::make_pair(type, std::forward<U>(insertee))); it = res.first; } return it->second; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::DataMap & ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) { if (ghost_type == _not_ghost) return data; return ghost_data; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline const typename ElementTypeMap<Stored, SupportType>::DataMap & ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) const { if (ghost_type == _not_ghost) return data; return ghost_data; } /* -------------------------------------------------------------------------- */ /// Works only if stored is a pointer to a class with a printself method template <class Stored, typename SupportType> void ElementTypeMap<Stored, SupportType>::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> [" << std::endl; for (auto gt : ghost_types) { const DataMap & data = getData(gt); for (auto & pair : data) { stream << space << space << ElementTypeMap::printType(pair.first, gt) << std::endl; } } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::ElementTypeMap() = default; /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::~ElementTypeMap() = default; /* -------------------------------------------------------------------------- */ /* ElementTypeMapArray */ /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> void ElementTypeMapArray<T, SupportType>::copy( const ElementTypeMapArray & other) { for (auto ghost_type : ghost_types) { for (auto type : this->elementTypes(_all_dimensions, ghost_types, _ek_not_defined)) { const auto & array_to_copy = other(type, ghost_type); auto & array = this->alloc(0, array_to_copy.getNbComponent(), type, ghost_type); array.copy(array_to_copy); } } } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline Array<T> & ElementTypeMapArray<T, SupportType>::alloc( UInt size, UInt nb_component, const SupportType & type, const GhostType & ghost_type, const T & default_value) { std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; Array<T> * tmp; auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) { std::stringstream sstr; sstr << this->id << ":" << type << ghost_id; tmp = &(Memory::alloc<T>(sstr.str(), size, nb_component, default_value)); std::stringstream sstrg; sstrg << ghost_type; // tmp->setTag(sstrg.str()); this->getData(ghost_type)[type] = tmp; } else { AKANTU_DEBUG_INFO( "The vector " << this->id << this->printType(type, ghost_type) << " already exists, it is resized instead of allocated."); tmp = it->second; it->second->resize(size); } return *tmp; } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::alloc(UInt size, UInt nb_component, const SupportType & type, const T & default_value) { this->alloc(size, nb_component, type, _not_ghost, default_value); this->alloc(size, nb_component, type, _ghost, default_value); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::free() { AKANTU_DEBUG_IN(); for (auto gt : ghost_types) { auto & data = this->getData(gt); for (auto & pair : data) { dealloc(pair.second->getID()); } data.clear(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::clear() { for (auto gt : ghost_types) { auto & data = this->getData(gt); for (auto & vect : data) { vect.second->clear(); } } } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> template <typename ST> inline void ElementTypeMapArray<T, SupportType>::set(const ST & value) { for (auto gt : ghost_types) { auto & data = this->getData(gt); for (auto & vect : data) { vect.second->set(value); } } } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline const Array<T> & ElementTypeMapArray<T, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) const { auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMapArray::printType(type, ghost_type) << " in this const ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> class(\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline Array<T> & ElementTypeMapArray<T, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) { auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMapArray::printType(type, ghost_type) << " in this ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> class (\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::setArray(const SupportType & type, const GhostType & ghost_type, const Array<T> & vect) { auto it = this->getData(ghost_type).find(type); if (AKANTU_DEBUG_TEST(dblWarning) && it != this->getData(ghost_type).end() && it->second != &vect) { AKANTU_DEBUG_WARNING( "The Array " << this->printType(type, ghost_type) << " is already registred, this call can lead to a memory leak."); } this->getData(ghost_type)[type] = &(const_cast<Array<T> &>(vect)); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::onElementsRemoved( const ElementTypeMapArray<UInt> & new_numbering) { for (auto gt : ghost_types) { for (auto & type : new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) { auto support_type = convertType<ElementType, SupportType>(type); if (this->exists(support_type, gt)) { const auto & renumbering = new_numbering(type, gt); if (renumbering.size() == 0) continue; auto & vect = this->operator()(support_type, gt); auto nb_component = vect.getNbComponent(); Array<T> tmp(renumbering.size(), nb_component); UInt new_size = 0; for (UInt i = 0; i < vect.size(); ++i) { UInt new_i = renumbering(i); if (new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component, vect.storage() + i * nb_component, nb_component * sizeof(T)); ++new_size; } } tmp.resize(new_size); vect.copy(tmp); } } } } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> void ElementTypeMapArray<T, SupportType>::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; for (UInt g = _not_ghost; g <= _ghost; ++g) { auto gt = (GhostType)g; const DataMap & data = this->getData(gt); typename DataMap::const_iterator it; for (it = data.begin(); it != data.end(); ++it) { stream << space << space << ElementTypeMapArray::printType(it->first, gt) << " [" << std::endl; it->second->printself(stream, indent + 3); stream << space << space << " ]" << std::endl; } } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /* SupportType Iterator */ /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator( DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek) : list_begin(list_begin), list_end(list_end), dim(dim), kind(ek) {} /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator( const type_iterator & it) : list_begin(it.list_begin), list_end(it.list_end), dim(it.dim), kind(it.kind) {} /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> typename ElementTypeMap<Stored, SupportType>::type_iterator & ElementTypeMap<Stored, SupportType>::type_iterator:: operator=(const type_iterator & it) { if (this != &it) { list_begin = it.list_begin; list_end = it.list_end; dim = it.dim; kind = it.kind; } return *this; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference ElementTypeMap<Stored, SupportType>::type_iterator::operator*() { return list_begin->first; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference ElementTypeMap<Stored, SupportType>::type_iterator::operator*() const { return list_begin->first; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator & ElementTypeMap<Stored, SupportType>::type_iterator::operator++() { ++list_begin; while ((list_begin != list_end) && (((dim != _all_dimensions) && (dim != Mesh::getSpatialDimension(list_begin->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(list_begin->first))))) ++list_begin; return *this; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> typename ElementTypeMap<Stored, SupportType>::type_iterator ElementTypeMap<Stored, SupportType>::type_iterator::operator++(int) { type_iterator tmp(*this); operator++(); return tmp; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline bool ElementTypeMap<Stored, SupportType>::type_iterator:: operator==(const type_iterator & other) const { return this->list_begin == other.list_begin; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline bool ElementTypeMap<Stored, SupportType>::type_iterator:: operator!=(const type_iterator & other) const { return this->list_begin != other.list_begin; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper ElementTypeMap<Stored, SupportType>::elementTypesImpl(UInt dim, GhostType ghost_type, ElementKind kind) const { return ElementTypesIteratorHelper(*this, dim, ghost_type, kind); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> template <typename... pack> typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper ElementTypeMap<Stored, SupportType>::elementTypesImpl( const use_named_args_t & unused, pack &&... _pack) const { return ElementTypesIteratorHelper(*this, unused, _pack...); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator ElementTypeMap<Stored, SupportType>::firstType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator b, e; b = getData(ghost_type).begin(); e = getData(ghost_type).end(); // loop until the first valid type while ((b != e) && (((dim != _all_dimensions) && (dim != Mesh::getSpatialDimension(b->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(b->first))))) ++b; return typename ElementTypeMap<Stored, SupportType>::type_iterator(b, e, dim, kind); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator ElementTypeMap<Stored, SupportType>::lastType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator e; e = getData(ghost_type).end(); return typename ElementTypeMap<Stored, SupportType>::type_iterator(e, e, dim, kind); } /* -------------------------------------------------------------------------- */ /// standard output stream operator template <class Stored, typename SupportType> inline std::ostream & operator<<(std::ostream & stream, const ElementTypeMap<Stored, SupportType> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ class ElementTypeMapArrayInitializer { protected: using CompFunc = std::function<UInt(const ElementType &, const GhostType &)>; public: ElementTypeMapArrayInitializer(const CompFunc & comp_func, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular) : comp_func(comp_func), spatial_dimension(spatial_dimension), ghost_type(ghost_type), element_kind(element_kind) {} const GhostType & ghostType() const { return ghost_type; } virtual UInt nbComponent(const ElementType & type) const { return comp_func(type, ghostType()); } protected: CompFunc comp_func; UInt spatial_dimension; GhostType ghost_type; ElementKind element_kind; }; /* -------------------------------------------------------------------------- */ class MeshElementTypeMapArrayInitializer : public ElementTypeMapArrayInitializer { using CompFunc = ElementTypeMapArrayInitializer::CompFunc; public: MeshElementTypeMapArrayInitializer( const Mesh & mesh, UInt nb_component = 1, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular, bool with_nb_element = false, bool with_nb_nodes_per_element = false) : MeshElementTypeMapArrayInitializer( mesh, [nb_component](const ElementType &, const GhostType &) -> UInt { return nb_component; }, spatial_dimension, ghost_type, element_kind, with_nb_element, with_nb_nodes_per_element) {} MeshElementTypeMapArrayInitializer( const Mesh & mesh, const CompFunc & comp_func, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular, bool with_nb_element = false, bool with_nb_nodes_per_element = false) : ElementTypeMapArrayInitializer(comp_func, spatial_dimension, ghost_type, element_kind), mesh(mesh), with_nb_element(with_nb_element), with_nb_nodes_per_element(with_nb_nodes_per_element) {} decltype(auto) elementTypes() const { return mesh.elementTypes(this->spatial_dimension, this->ghost_type, this->element_kind); } virtual UInt size(const ElementType & type) const { if (with_nb_element) return mesh.getNbElement(type, this->ghost_type); return 0; } UInt nbComponent(const ElementType & type) const override { UInt res = ElementTypeMapArrayInitializer::nbComponent(type); if (with_nb_nodes_per_element) return (res * mesh.getNbNodesPerElement(type)); return res; } protected: const Mesh & mesh; bool with_nb_element; bool with_nb_nodes_per_element; }; /* -------------------------------------------------------------------------- */ class FEEngineElementTypeMapArrayInitializer : public MeshElementTypeMapArrayInitializer { public: FEEngineElementTypeMapArrayInitializer( const FEEngine & fe_engine, UInt nb_component = 1, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular); FEEngineElementTypeMapArrayInitializer( const FEEngine & fe_engine, const ElementTypeMapArrayInitializer::CompFunc & nb_component, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular); UInt size(const ElementType & type) const override; using ElementTypesIteratorHelper = ElementTypeMapArray<Real, ElementType>::ElementTypesIteratorHelper; ElementTypesIteratorHelper elementTypes() const; protected: const FEEngine & fe_engine; }; /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> template <class Func> void ElementTypeMapArray<T, SupportType>::initialize(const Func & f, const T & default_value, bool do_not_default) { auto ghost_type = f.ghostType(); for (auto & type : f.elementTypes()) { if (not this->exists(type, ghost_type)) if (do_not_default) { auto & array = this->alloc(0, f.nbComponent(type), type, ghost_type); array.resize(f.size(type)); } else { this->alloc(f.size(type), f.nbComponent(type), type, ghost_type, default_value); } else { auto & array = this->operator()(type, ghost_type); if (not do_not_default) array.resize(f.size(type), default_value); else array.resize(f.size(type)); } } } /* -------------------------------------------------------------------------- */ /** * All parameters are named optionals * \param _nb_component a functor giving the number of components per * (ElementType, GhostType) pair or a scalar giving a unique number of * components * regardless of type * \param _spatial_dimension a filter for the elements of a specific dimension * \param _element_kind filter with element kind (_ek_regular, _ek_structural, * ...) * \param _with_nb_element allocate the arrays with the number of elements for * each * type in the mesh * \param _with_nb_nodes_per_element multiply the number of components by the * number of nodes per element * \param _default_value default inital value * \param _do_not_default do not initialize the allocated arrays * \param _ghost_type filter a type of ghost */ template <typename T, typename SupportType> template <typename... pack> void ElementTypeMapArray<T, SupportType>::initialize(const Mesh & mesh, pack &&... _pack) { GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _casper); bool all_ghost_types = requested_ghost_type == _casper; for (auto ghost_type : ghost_types) { if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types)) continue; // This thing should have a UInt or functor type auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1); auto functor = MeshElementTypeMapArrayInitializer( mesh, std::forward<decltype(nb_components)>(nb_components), OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()), ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular), OPTIONAL_NAMED_ARG(with_nb_element, false), OPTIONAL_NAMED_ARG(with_nb_nodes_per_element, false)); this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()), OPTIONAL_NAMED_ARG(do_not_default, false)); } } /* -------------------------------------------------------------------------- */ /** * All parameters are named optionals * \param _nb_component a functor giving the number of components per * (ElementType, GhostType) pair or a scalar giving a unique number of * components * regardless of type * \param _spatial_dimension a filter for the elements of a specific dimension * \param _element_kind filter with element kind (_ek_regular, _ek_structural, * ...) * \param _default_value default inital value * \param _do_not_default do not initialize the allocated arrays * \param _ghost_type filter a specific ghost type * \param _all_ghost_types get all ghost types */ template <typename T, typename SupportType> template <typename... pack> void ElementTypeMapArray<T, SupportType>::initialize(const FEEngine & fe_engine, pack &&... _pack) { bool all_ghost_types = OPTIONAL_NAMED_ARG(all_ghost_types, true); GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _not_ghost); for (auto ghost_type : ghost_types) { if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types)) continue; auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1); auto functor = FEEngineElementTypeMapArrayInitializer( fe_engine, std::forward<decltype(nb_components)>(nb_components), OPTIONAL_NAMED_ARG(spatial_dimension, UInt(-2)), ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular)); this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()), OPTIONAL_NAMED_ARG(do_not_default, false)); } } /* -------------------------------------------------------------------------- */ template <class T, typename SupportType> inline T & ElementTypeMapArray<T, SupportType>:: operator()(const Element & element, UInt component) { return this->operator()(element.type, element.ghost_type)(element.element, component); } /* -------------------------------------------------------------------------- */ template <class T, typename SupportType> inline const T & ElementTypeMapArray<T, SupportType>:: operator()(const Element & element, UInt component) const { return this->operator()(element.type, element.ghost_type)(element.element, component); } } // namespace akantu #endif /* __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ */ diff --git a/src/mesh/group_manager.cc b/src/mesh/group_manager.cc index a18c02007..98c067ce4 100644 --- a/src/mesh/group_manager.cc +++ b/src/mesh/group_manager.cc @@ -1,1040 +1,1040 @@ /** * @file group_manager.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@gmail.com> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Mon Aug 17 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Stores information about ElementGroup and NodeGroup * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "group_manager.hh" #include "aka_csr.hh" #include "data_accessor.hh" #include "element_group.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_accessor.hh" #include "mesh_utils.hh" #include "node_group.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <iterator> #include <list> #include <numeric> #include <queue> #include <sstream> #include <utility> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ GroupManager::GroupManager(const Mesh & mesh, const ID & id, const MemoryID & mem_id) : id(id), memory_id(mem_id), mesh(mesh) { AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ GroupManager::~GroupManager() { auto eit = element_groups.begin(); auto eend = element_groups.end(); for (; eit != eend; ++eit) delete (eit->second); auto nit = node_groups.begin(); auto nend = node_groups.end(); for (; nit != nend; ++nit) delete (nit->second); } /* -------------------------------------------------------------------------- */ NodeGroup & GroupManager::createNodeGroup(const std::string & group_name, bool replace_group) { AKANTU_DEBUG_IN(); auto it = node_groups.find(group_name); if (it != node_groups.end()) { if (replace_group) { it->second->empty(); AKANTU_DEBUG_OUT(); return *(it->second); } else AKANTU_EXCEPTION( "Trying to create a node group that already exists:" << group_name); } std::stringstream sstr; sstr << this->id << ":" << group_name << "_node_group"; NodeGroup * node_group = new NodeGroup(group_name, mesh, sstr.str(), memory_id); node_groups[group_name] = node_group; AKANTU_DEBUG_OUT(); return *node_group; } /* -------------------------------------------------------------------------- */ template <typename T> NodeGroup & GroupManager::createFilteredNodeGroup(const std::string & group_name, const NodeGroup & source_node_group, T & filter) { AKANTU_DEBUG_IN(); NodeGroup & node_group = this->createNodeGroup(group_name); node_group.append(source_node_group); if (T::type == FilterFunctor::_node_filter_functor) { node_group.applyNodeFilter(filter); } else { AKANTU_ERROR("ElementFilter cannot be applied to NodeGroup yet." << " Needs to be implemented."); } AKANTU_DEBUG_OUT(); return node_group; } /* -------------------------------------------------------------------------- */ void GroupManager::destroyNodeGroup(const std::string & group_name) { AKANTU_DEBUG_IN(); auto nit = node_groups.find(group_name); auto nend = node_groups.end(); if (nit != nend) { delete (nit->second); node_groups.erase(nit); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementGroup & GroupManager::createElementGroup(const std::string & group_name, UInt dimension, bool replace_group) { AKANTU_DEBUG_IN(); NodeGroup & new_node_group = createNodeGroup(group_name + "_nodes", replace_group); auto it = element_groups.find(group_name); if (it != element_groups.end()) { if (replace_group) { it->second->empty(); AKANTU_DEBUG_OUT(); return *(it->second); } else AKANTU_EXCEPTION("Trying to create a element group that already exists:" << group_name); } std::stringstream sstr; sstr << this->id << ":" << group_name << "_element_group"; ElementGroup * element_group = new ElementGroup( group_name, mesh, new_node_group, dimension, sstr.str(), memory_id); std::stringstream sstr_nodes; sstr_nodes << group_name << "_nodes"; node_groups[sstr_nodes.str()] = &new_node_group; element_groups[group_name] = element_group; AKANTU_DEBUG_OUT(); return *element_group; } /* -------------------------------------------------------------------------- */ void GroupManager::destroyElementGroup(const std::string & group_name, bool destroy_node_group) { AKANTU_DEBUG_IN(); auto eit = element_groups.find(group_name); auto eend = element_groups.end(); if (eit != eend) { if (destroy_node_group) destroyNodeGroup(eit->second->getNodeGroup().getName()); delete (eit->second); element_groups.erase(eit); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GroupManager::destroyAllElementGroups(bool destroy_node_groups) { AKANTU_DEBUG_IN(); auto eit = element_groups.begin(); auto eend = element_groups.end(); for (; eit != eend; ++eit) { if (destroy_node_groups) destroyNodeGroup(eit->second->getNodeGroup().getName()); delete (eit->second); } element_groups.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementGroup & GroupManager::createElementGroup(const std::string & group_name, UInt dimension, NodeGroup & node_group) { AKANTU_DEBUG_IN(); if (element_groups.find(group_name) != element_groups.end()) AKANTU_EXCEPTION( "Trying to create a element group that already exists:" << group_name); ElementGroup * element_group = new ElementGroup(group_name, mesh, node_group, dimension, id + ":" + group_name + "_element_group", memory_id); element_groups[group_name] = element_group; AKANTU_DEBUG_OUT(); return *element_group; } /* -------------------------------------------------------------------------- */ template <typename T> ElementGroup & GroupManager::createFilteredElementGroup( const std::string & group_name, UInt dimension, const NodeGroup & node_group, T & filter) { AKANTU_DEBUG_IN(); ElementGroup * element_group = nullptr; if (T::type == FilterFunctor::_node_filter_functor) { NodeGroup & filtered_node_group = this->createFilteredNodeGroup( group_name + "_nodes", node_group, filter); element_group = &(this->createElementGroup(group_name, dimension, filtered_node_group)); } else if (T::type == FilterFunctor::_element_filter_functor) { AKANTU_ERROR( "Cannot handle an ElementFilter yet. Needs to be implemented."); } AKANTU_DEBUG_OUT(); return *element_group; } /* -------------------------------------------------------------------------- */ class ClusterSynchronizer : public DataAccessor<Element> { using DistantIDs = std::set<std::pair<UInt, UInt>>; public: ClusterSynchronizer(GroupManager & group_manager, UInt element_dimension, std::string cluster_name_prefix, ElementTypeMapArray<UInt> & element_to_fragment, const ElementSynchronizer & element_synchronizer, UInt nb_cluster) : group_manager(group_manager), element_dimension(element_dimension), cluster_name_prefix(std::move(cluster_name_prefix)), element_to_fragment(element_to_fragment), element_synchronizer(element_synchronizer), nb_cluster(nb_cluster) {} UInt synchronize() { Communicator & comm = Communicator::getStaticCommunicator(); UInt rank = comm.whoAmI(); UInt nb_proc = comm.getNbProc(); /// find starting index to renumber local clusters Array<UInt> nb_cluster_per_proc(nb_proc); nb_cluster_per_proc(rank) = nb_cluster; comm.allGather(nb_cluster_per_proc); starting_index = std::accumulate(nb_cluster_per_proc.begin(), nb_cluster_per_proc.begin() + rank, 0); UInt global_nb_fragment = std::accumulate(nb_cluster_per_proc.begin() + rank, nb_cluster_per_proc.end(), starting_index); /// create the local to distant cluster pairs with neighbors element_synchronizer.synchronizeOnce(*this, _gst_gm_clusters); /// count total number of pairs Array<int> nb_pairs(nb_proc); // This is potentially a bug for more than // 2**31 pairs, but due to a all gatherv after // it must be int to match MPI interfaces nb_pairs(rank) = distant_ids.size(); comm.allGather(nb_pairs); UInt total_nb_pairs = std::accumulate(nb_pairs.begin(), nb_pairs.end(), 0); /// generate pairs global array UInt local_pair_index = std::accumulate(nb_pairs.storage(), nb_pairs.storage() + rank, 0); Array<UInt> total_pairs(total_nb_pairs, 2); for (auto & ids : distant_ids) { total_pairs(local_pair_index, 0) = ids.first; total_pairs(local_pair_index, 1) = ids.second; ++local_pair_index; } /// communicate pairs to all processors nb_pairs *= 2; comm.allGatherV(total_pairs, nb_pairs); /// renumber clusters /// generate fragment list std::vector<std::set<UInt>> global_clusters; UInt total_nb_cluster = 0; Array<bool> is_fragment_in_cluster(global_nb_fragment, 1, false); std::queue<UInt> fragment_check_list; while (total_pairs.size() != 0) { /// create a new cluster ++total_nb_cluster; global_clusters.resize(total_nb_cluster); std::set<UInt> & current_cluster = global_clusters[total_nb_cluster - 1]; UInt first_fragment = total_pairs(0, 0); UInt second_fragment = total_pairs(0, 1); total_pairs.erase(0); fragment_check_list.push(first_fragment); fragment_check_list.push(second_fragment); while (!fragment_check_list.empty()) { UInt current_fragment = fragment_check_list.front(); UInt * total_pairs_end = total_pairs.storage() + total_pairs.size() * 2; UInt * fragment_found = std::find(total_pairs.storage(), total_pairs_end, current_fragment); if (fragment_found != total_pairs_end) { UInt position = fragment_found - total_pairs.storage(); UInt pair = position / 2; UInt other_index = (position + 1) % 2; fragment_check_list.push(total_pairs(pair, other_index)); total_pairs.erase(pair); } else { fragment_check_list.pop(); current_cluster.insert(current_fragment); is_fragment_in_cluster(current_fragment) = true; } } } /// add to FragmentToCluster all local fragments for (UInt c = 0; c < global_nb_fragment; ++c) { if (!is_fragment_in_cluster(c)) { ++total_nb_cluster; global_clusters.resize(total_nb_cluster); std::set<UInt> & current_cluster = global_clusters[total_nb_cluster - 1]; current_cluster.insert(c); } } /// reorganize element groups to match global clusters for (UInt c = 0; c < global_clusters.size(); ++c) { /// create new element group corresponding to current cluster std::stringstream sstr; sstr << cluster_name_prefix << "_" << c; ElementGroup & cluster = group_manager.createElementGroup(sstr.str(), element_dimension, true); auto it = global_clusters[c].begin(); auto end = global_clusters[c].end(); /// append to current element group all fragments that belong to /// the same cluster if they exist for (; it != end; ++it) { Int local_index = *it - starting_index; if (local_index < 0 || local_index >= Int(nb_cluster)) continue; std::stringstream tmp_sstr; tmp_sstr << "tmp_" << cluster_name_prefix << "_" << local_index; auto eg_it = group_manager.element_group_find(tmp_sstr.str()); AKANTU_DEBUG_ASSERT(eg_it != group_manager.element_group_end(), "Temporary fragment \"" << tmp_sstr.str() << "\" not found"); cluster.append(*(eg_it->second)); group_manager.destroyElementGroup(tmp_sstr.str(), true); } } return total_nb_cluster; } private: /// functions for parallel communications inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override { if (tag == _gst_gm_clusters) return elements.size() * sizeof(UInt); return 0; } inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override { if (tag != _gst_gm_clusters) return; Array<Element>::const_iterator<> el_it = elements.begin(); Array<Element>::const_iterator<> el_end = elements.end(); for (; el_it != el_end; ++el_it) { const Element & el = *el_it; /// for each element pack its global cluster index buffer << element_to_fragment(el.type, el.ghost_type)(el.element) + starting_index; } } inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override { if (tag != _gst_gm_clusters) return; Array<Element>::const_iterator<> el_it = elements.begin(); Array<Element>::const_iterator<> el_end = elements.end(); for (; el_it != el_end; ++el_it) { UInt distant_cluster; buffer >> distant_cluster; const Element & el = *el_it; UInt local_cluster = element_to_fragment(el.type, el.ghost_type)(el.element) + starting_index; distant_ids.insert(std::make_pair(local_cluster, distant_cluster)); } } private: GroupManager & group_manager; UInt element_dimension; std::string cluster_name_prefix; ElementTypeMapArray<UInt> & element_to_fragment; const ElementSynchronizer & element_synchronizer; UInt nb_cluster; DistantIDs distant_ids; UInt starting_index; }; /* -------------------------------------------------------------------------- */ /// \todo this function doesn't work in 1D UInt GroupManager::createBoundaryGroupFromGeometry() { UInt spatial_dimension = mesh.getSpatialDimension(); return createClusters(spatial_dimension - 1, "boundary"); } /* -------------------------------------------------------------------------- */ UInt GroupManager::createClusters( UInt element_dimension, Mesh & mesh_facets, std::string cluster_name_prefix, const GroupManager::ClusteringFilter & filter) { return createClusters(element_dimension, std::move(cluster_name_prefix), filter, mesh_facets); } /* -------------------------------------------------------------------------- */ UInt GroupManager::createClusters( UInt element_dimension, std::string cluster_name_prefix, const GroupManager::ClusteringFilter & filter) { std::unique_ptr<Mesh> mesh_facets; if (!mesh_facets && element_dimension > 0) { MeshAccessor mesh_accessor(const_cast<Mesh &>(mesh)); mesh_facets = std::make_unique<Mesh>(mesh.getSpatialDimension(), mesh_accessor.getNodesSharedPtr(), "mesh_facets_for_clusters"); mesh_facets->defineMeshParent(mesh); MeshUtils::buildAllFacets(mesh, *mesh_facets, element_dimension, element_dimension - 1); } return createClusters(element_dimension, std::move(cluster_name_prefix), filter, *mesh_facets); } /* -------------------------------------------------------------------------- */ //// \todo if needed element list construction can be optimized by //// templating the filter class UInt GroupManager::createClusters(UInt element_dimension, const std::string & cluster_name_prefix, const GroupManager::ClusteringFilter & filter, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt nb_proc = mesh.getCommunicator().getNbProc(); std::string tmp_cluster_name_prefix = cluster_name_prefix; ElementTypeMapArray<UInt> * element_to_fragment = nullptr; if (nb_proc > 1 && mesh.isDistributed()) { element_to_fragment = new ElementTypeMapArray<UInt>("element_to_fragment", id, memory_id); element_to_fragment->initialize( mesh, _nb_component = 1, _spatial_dimension = element_dimension, _element_kind = _ek_not_defined, _with_nb_element = true); // mesh.initElementTypeMapArray(*element_to_fragment, 1, element_dimension, // false, _ek_not_defined, true); tmp_cluster_name_prefix = "tmp_" + tmp_cluster_name_prefix; } ElementTypeMapArray<bool> seen_elements("seen_elements", id, memory_id); seen_elements.initialize(mesh, _spatial_dimension = element_dimension, _element_kind = _ek_not_defined, _with_nb_element = true); // mesh.initElementTypeMapArray(seen_elements, 1, element_dimension, false, // _ek_not_defined, true); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Element el; el.ghost_type = ghost_type; Mesh::type_iterator type_it = mesh.firstType(element_dimension, ghost_type, _ek_not_defined); Mesh::type_iterator type_end = mesh.lastType(element_dimension, ghost_type, _ek_not_defined); for (; type_it != type_end; ++type_it) { el.type = *type_it; UInt nb_element = mesh.getNbElement(*type_it, ghost_type); Array<bool> & seen_elements_array = seen_elements(el.type, ghost_type); for (UInt e = 0; e < nb_element; ++e) { el.element = e; if (!filter(el)) seen_elements_array(e) = true; } } } Array<bool> checked_node(mesh.getNbNodes(), 1, false); UInt nb_cluster = 0; /// keep looping until all elements are seen for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Element uns_el; uns_el.ghost_type = ghost_type; Mesh::type_iterator type_it = mesh.firstType(element_dimension, ghost_type, _ek_not_defined); Mesh::type_iterator type_end = mesh.lastType(element_dimension, ghost_type, _ek_not_defined); for (; type_it != type_end; ++type_it) { uns_el.type = *type_it; Array<bool> & seen_elements_vec = seen_elements(uns_el.type, uns_el.ghost_type); for (UInt e = 0; e < seen_elements_vec.size(); ++e) { // skip elements that have been already seen if (seen_elements_vec(e) == true) continue; // set current element uns_el.element = e; seen_elements_vec(e) = true; /// create a new cluster std::stringstream sstr; sstr << tmp_cluster_name_prefix << "_" << nb_cluster; ElementGroup & cluster = createElementGroup(sstr.str(), element_dimension, true); ++nb_cluster; // point element are cluster by themself if (element_dimension == 0) { cluster.add(uns_el); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(uns_el.type); Vector<UInt> connect = mesh.getConnectivity(uns_el.type, uns_el.ghost_type) .begin(nb_nodes_per_element)[uns_el.element]; for (UInt n = 0; n < nb_nodes_per_element; ++n) { /// add element's nodes to the cluster UInt node = connect[n]; if (!checked_node(node)) { cluster.addNode(node); checked_node(node) = true; } } continue; } std::queue<Element> element_to_add; element_to_add.push(uns_el); /// keep looping until current cluster is complete (no more /// connected elements) while (!element_to_add.empty()) { /// take first element and erase it in the queue Element el = element_to_add.front(); element_to_add.pop(); /// if parallel, store cluster index per element if (nb_proc > 1 && mesh.isDistributed()) (*element_to_fragment)(el.type, el.ghost_type)(el.element) = nb_cluster - 1; /// add current element to the cluster cluster.add(el); const Array<Element> & element_to_facet = mesh_facets.getSubelementToElement(el.type, el.ghost_type); UInt nb_facet_per_element = element_to_facet.getNbComponent(); for (UInt f = 0; f < nb_facet_per_element; ++f) { const Element & facet = element_to_facet(el.element, f); if (facet == ElementNull) continue; const std::vector<Element> & connected_elements = mesh_facets.getElementToSubelement( facet.type, facet.ghost_type)(facet.element); for (UInt elem = 0; elem < connected_elements.size(); ++elem) { const Element & check_el = connected_elements[elem]; // check if this element has to be skipped if (check_el == ElementNull || check_el == el) continue; Array<bool> & seen_elements_vec_current = seen_elements(check_el.type, check_el.ghost_type); if (seen_elements_vec_current(check_el.element) == false) { seen_elements_vec_current(check_el.element) = true; element_to_add.push(check_el); } } } UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type); Vector<UInt> connect = mesh.getConnectivity(el.type, el.ghost_type) .begin(nb_nodes_per_element)[el.element]; for (UInt n = 0; n < nb_nodes_per_element; ++n) { /// add element's nodes to the cluster UInt node = connect[n]; if (!checked_node(node)) { cluster.addNode(node, false); checked_node(node) = true; } } } } } } if (nb_proc > 1 && mesh.isDistributed()) { ClusterSynchronizer cluster_synchronizer( *this, element_dimension, cluster_name_prefix, *element_to_fragment, this->mesh.getElementSynchronizer(), nb_cluster); nb_cluster = cluster_synchronizer.synchronize(); delete element_to_fragment; } if (mesh.isDistributed()) this->synchronizeGroupNames(); AKANTU_DEBUG_OUT(); return nb_cluster; } /* -------------------------------------------------------------------------- */ template <typename T> void GroupManager::createGroupsFromMeshData(const std::string & dataset_name) { std::set<std::string> group_names; const ElementTypeMapArray<T> & datas = mesh.getData<T>(dataset_name); using type_iterator = typename ElementTypeMapArray<T>::type_iterator; std::map<std::string, UInt> group_dim; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { type_iterator type_it = datas.firstType(_all_dimensions, *gt); type_iterator type_end = datas.lastType(_all_dimensions, *gt); for (; type_it != type_end; ++type_it) { const Array<T> & dataset = datas(*type_it, *gt); UInt nb_element = mesh.getNbElement(*type_it, *gt); AKANTU_DEBUG_ASSERT(dataset.size() == nb_element, "Not the same number of elements (" << *type_it << ":" << *gt << ") in the map from MeshData (" << dataset.size() << ") " << dataset_name << " and in the mesh (" << nb_element << ")!"); for (UInt e(0); e < nb_element; ++e) { std::stringstream sstr; sstr << dataset(e); std::string gname = sstr.str(); group_names.insert(gname); auto it = group_dim.find(gname); if (it == group_dim.end()) { group_dim[gname] = mesh.getSpatialDimension(*type_it); } else { it->second = std::max(it->second, mesh.getSpatialDimension(*type_it)); } } } } auto git = group_names.begin(); auto gend = group_names.end(); for (; git != gend; ++git) createElementGroup(*git, group_dim[*git]); if (mesh.isDistributed()) this->synchronizeGroupNames(); Element el; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { el.ghost_type = *gt; type_iterator type_it = datas.firstType(_all_dimensions, *gt); type_iterator type_end = datas.lastType(_all_dimensions, *gt); for (; type_it != type_end; ++type_it) { el.type = *type_it; const Array<T> & dataset = datas(*type_it, *gt); UInt nb_element = mesh.getNbElement(*type_it, *gt); AKANTU_DEBUG_ASSERT(dataset.size() == nb_element, "Not the same number of elements in the map from " "MeshData and in the mesh!"); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(el.type); Array<UInt>::const_iterator<Vector<UInt>> cit = mesh.getConnectivity(*type_it, *gt).begin(nb_nodes_per_element); for (UInt e(0); e < nb_element; ++e, ++cit) { el.element = e; std::stringstream sstr; sstr << dataset(e); ElementGroup & group = getElementGroup(sstr.str()); group.add(el, false, false); const Vector<UInt> & connect = *cit; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connect[n]; group.addNode(node, false); } } } } git = group_names.begin(); for (; git != gend; ++git) { getElementGroup(*git).optimize(); } } template void GroupManager::createGroupsFromMeshData<std::string>( const std::string & dataset_name); template void GroupManager::createGroupsFromMeshData<UInt>(const std::string & dataset_name); /* -------------------------------------------------------------------------- */ void GroupManager::createElementGroupFromNodeGroup( const std::string & name, const std::string & node_group_name, UInt dimension) { NodeGroup & node_group = getNodeGroup(node_group_name); ElementGroup & group = createElementGroup(name, dimension, node_group); group.fillFromNodeGroup(); } /* -------------------------------------------------------------------------- */ void GroupManager::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "GroupManager [" << std::endl; std::set<std::string> node_group_seen; for (auto it(element_group_begin()); it != element_group_end(); ++it) { it->second->printself(stream, indent + 1); node_group_seen.insert(it->second->getNodeGroup().getName()); } for (auto it(node_group_begin()); it != node_group_end(); ++it) { if (node_group_seen.find(it->second->getName()) == node_group_seen.end()) it->second->printself(stream, indent + 1); } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ UInt GroupManager::getNbElementGroups(UInt dimension) const { if (dimension == _all_dimensions) return element_groups.size(); auto it = element_groups.begin(); auto end = element_groups.end(); UInt count = 0; for (; it != end; ++it) count += (it->second->getDimension() == dimension); return count; } /* -------------------------------------------------------------------------- */ void GroupManager::checkAndAddGroups(CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); UInt nb_node_group; buffer >> nb_node_group; AKANTU_DEBUG_INFO("Received " << nb_node_group << " node group names"); for (UInt ng = 0; ng < nb_node_group; ++ng) { std::string node_group_name; buffer >> node_group_name; if (node_groups.find(node_group_name) == node_groups.end()) { this->createNodeGroup(node_group_name); } AKANTU_DEBUG_INFO("Received node goup name: " << node_group_name); } UInt nb_element_group; buffer >> nb_element_group; AKANTU_DEBUG_INFO("Received " << nb_element_group << " element group names"); for (UInt eg = 0; eg < nb_element_group; ++eg) { std::string element_group_name; buffer >> element_group_name; std::string node_group_name; buffer >> node_group_name; UInt dim; buffer >> dim; AKANTU_DEBUG_INFO("Received element group name: " << element_group_name << " corresponding to a " << Int(dim) << "D group with node group " << node_group_name); NodeGroup & node_group = *node_groups[node_group_name]; if (element_groups.find(element_group_name) == element_groups.end()) { this->createElementGroup(element_group_name, dim, node_group); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GroupManager::fillBufferWithGroupNames( DynamicCommunicationBuffer & comm_buffer) const { AKANTU_DEBUG_IN(); // packing node group names; UInt nb_groups = this->node_groups.size(); comm_buffer << nb_groups; AKANTU_DEBUG_INFO("Sending " << nb_groups << " node group names"); auto nnames_it = node_groups.begin(); auto nnames_end = node_groups.end(); for (; nnames_it != nnames_end; ++nnames_it) { std::string node_group_name = nnames_it->first; comm_buffer << node_group_name; AKANTU_DEBUG_INFO("Sending node goupe name: " << node_group_name); } // packing element group names with there associated node group name nb_groups = this->element_groups.size(); comm_buffer << nb_groups; AKANTU_DEBUG_INFO("Sending " << nb_groups << " element group names"); auto gnames_it = this->element_groups.begin(); auto gnames_end = this->element_groups.end(); for (; gnames_it != gnames_end; ++gnames_it) { ElementGroup & element_group = *(gnames_it->second); std::string element_group_name = gnames_it->first; std::string node_group_name = element_group.getNodeGroup().getName(); UInt dim = element_group.getDimension(); comm_buffer << element_group_name; comm_buffer << node_group_name; comm_buffer << dim; AKANTU_DEBUG_INFO("Sending element group name: " << element_group_name << " corresponding to a " << Int(dim) << "D group with the node group " << node_group_name); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GroupManager::synchronizeGroupNames() { AKANTU_DEBUG_IN(); const Communicator & comm = mesh.getCommunicator(); Int nb_proc = comm.getNbProc(); Int my_rank = comm.whoAmI(); if (nb_proc == 1) return; if (my_rank == 0) { for (Int p = 1; p < nb_proc; ++p) { CommunicationStatus status; comm.probe<char>(p, p, status); AKANTU_DEBUG_INFO("Got " << printMemorySize<char>(status.size()) << " from proc " << p); CommunicationBuffer recv_buffer(status.size()); comm.receive(recv_buffer, p, p); this->checkAndAddGroups(recv_buffer); } DynamicCommunicationBuffer comm_buffer; this->fillBufferWithGroupNames(comm_buffer); UInt buffer_size = comm_buffer.size(); comm.broadcast(buffer_size, 0); AKANTU_DEBUG_INFO("Initiating broadcast with " << printMemorySize<char>(comm_buffer.size())); comm.broadcast(comm_buffer, 0); } else { DynamicCommunicationBuffer comm_buffer; this->fillBufferWithGroupNames(comm_buffer); AKANTU_DEBUG_INFO("Sending " << printMemorySize<char>(comm_buffer.size()) << " to proc " << 0); comm.send(comm_buffer, 0, my_rank); UInt buffer_size = 0; comm.broadcast(buffer_size, 0); AKANTU_DEBUG_INFO("Receiving broadcast with " << printMemorySize<char>(comm_buffer.size())); CommunicationBuffer recv_buffer(buffer_size); comm.broadcast(recv_buffer, 0); this->checkAndAddGroups(recv_buffer); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ const ElementGroup & GroupManager::getElementGroup(const std::string & name) const { auto it = element_group_find(name); if (it == element_group_end()) { AKANTU_EXCEPTION("There are no element groups named " << name << " associated to the group manager: " << id); } return *(it->second); } /* -------------------------------------------------------------------------- */ ElementGroup & GroupManager::getElementGroup(const std::string & name) { auto it = element_group_find(name); if (it == element_group_end()) { AKANTU_EXCEPTION("There are no element groups named " << name << " associated to the group manager: " << id); } return *(it->second); } /* -------------------------------------------------------------------------- */ const NodeGroup & GroupManager::getNodeGroup(const std::string & name) const { auto it = node_group_find(name); if (it == node_group_end()) { AKANTU_EXCEPTION("There are no node groups named " << name << " associated to the group manager: " << id); } return *(it->second); } /* -------------------------------------------------------------------------- */ NodeGroup & GroupManager::getNodeGroup(const std::string & name) { auto it = node_group_find(name); if (it == node_group_end()) { AKANTU_EXCEPTION("There are no node groups named " << name << " associated to the group manager: " << id); } return *(it->second); } } // namespace akantu diff --git a/src/mesh/group_manager.hh b/src/mesh/group_manager.hh index 56998407b..242dd2ef4 100644 --- a/src/mesh/group_manager.hh +++ b/src/mesh/group_manager.hh @@ -1,316 +1,316 @@ /** * @file group_manager.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@gmail.com> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Mon Nov 16 2015 + * @date last modification: Wed Feb 07 2018 * * @brief Stores information relevent to the notion of element and nodes - *groups. + * groups. * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GROUP_MANAGER_HH__ #define __AKANTU_GROUP_MANAGER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_type_map.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ namespace akantu { class ElementGroup; class NodeGroup; class Mesh; class Element; class ElementSynchronizer; template <bool> class CommunicationBufferTemplated; namespace dumper { class Field; } } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ class GroupManager { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ private: #ifdef SWIGPYTHON public: using ElementGroups = std::map<std::string, ElementGroup *>; using NodeGroups = std::map<std::string, NodeGroup *>; private: #else using ElementGroups = std::map<std::string, ElementGroup *>; using NodeGroups = std::map<std::string, NodeGroup *>; #endif public: using GroupManagerTypeSet = std::set<ElementType>; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: GroupManager(const Mesh & mesh, const ID & id = "group_manager", const MemoryID & memory_id = 0); virtual ~GroupManager(); /* ------------------------------------------------------------------------ */ /* Groups iterators */ /* ------------------------------------------------------------------------ */ public: using node_group_iterator = NodeGroups::iterator; using element_group_iterator = ElementGroups::iterator; using const_node_group_iterator = NodeGroups::const_iterator; using const_element_group_iterator = ElementGroups::const_iterator; #ifndef SWIG #define AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(group_type, function, \ param_in, param_out) \ inline BOOST_PP_CAT(BOOST_PP_CAT(const_, group_type), _iterator) \ BOOST_PP_CAT(BOOST_PP_CAT(group_type, _), function)(param_in) const { \ return BOOST_PP_CAT(group_type, s).function(param_out); \ }; \ \ inline BOOST_PP_CAT(group_type, _iterator) \ BOOST_PP_CAT(BOOST_PP_CAT(group_type, _), function)(param_in) { \ return BOOST_PP_CAT(group_type, s).function(param_out); \ } #define AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(group_type, function) \ AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION( \ group_type, function, BOOST_PP_EMPTY(), BOOST_PP_EMPTY()) AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(node_group, begin); AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(node_group, end); AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(element_group, begin); AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(element_group, end); AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(element_group, find, const std::string & name, name); AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(node_group, find, const std::string & name, name); #endif /* ------------------------------------------------------------------------ */ /* Clustering filter */ /* ------------------------------------------------------------------------ */ public: class ClusteringFilter { public: virtual bool operator()(const Element &) const { return true; } }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// create an empty node group NodeGroup & createNodeGroup(const std::string & group_name, bool replace_group = false); /// create a node group from another node group but filtered template <typename T> NodeGroup & createFilteredNodeGroup(const std::string & group_name, const NodeGroup & node_group, T & filter); /// destroy a node group void destroyNodeGroup(const std::string & group_name); /// create an element group and the associated node group ElementGroup & createElementGroup(const std::string & group_name, UInt dimension = _all_dimensions, bool replace_group = false); /// create an element group from another element group but filtered template <typename T> ElementGroup & createFilteredElementGroup(const std::string & group_name, UInt dimension, const NodeGroup & node_group, T & filter); /// destroy an element group and the associated node group void destroyElementGroup(const std::string & group_name, bool destroy_node_group = false); /// destroy all element groups and the associated node groups void destroyAllElementGroups(bool destroy_node_groups = false); /// create a element group using an existing node group ElementGroup & createElementGroup(const std::string & group_name, UInt dimension, NodeGroup & node_group); /// create groups based on values stored in a given mesh data template <typename T> void createGroupsFromMeshData(const std::string & dataset_name); /// create boundaries group by a clustering algorithm \todo extend to parallel UInt createBoundaryGroupFromGeometry(); /// create element clusters for a given dimension UInt createClusters(UInt element_dimension, Mesh & mesh_facets, std::string cluster_name_prefix = "cluster", const ClusteringFilter & filter = ClusteringFilter()); /// create element clusters for a given dimension UInt createClusters(UInt element_dimension, std::string cluster_name_prefix = "cluster", const ClusteringFilter & filter = ClusteringFilter()); private: /// create element clusters for a given dimension UInt createClusters(UInt element_dimension, const std::string & cluster_name_prefix, const ClusteringFilter & filter, Mesh & mesh_facets); public: /// Create an ElementGroup based on a NodeGroup void createElementGroupFromNodeGroup(const std::string & name, const std::string & node_group, UInt dimension = _all_dimensions); virtual void printself(std::ostream & stream, int indent = 0) const; /// this function insure that the group names are present on all processors /// /!\ it is a SMP call void synchronizeGroupNames(); /// register an elemental field to the given group name (overloading for /// ElementalPartionField) #ifndef SWIG template <typename T, template <bool> class dump_type> dumper::Field * createElementalField( const ElementTypeMapArray<T> & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem = ElementTypeMap<UInt>()); /// register an elemental field to the given group name (overloading for /// ElementalField) template <typename T, template <class> class ret_type, template <class, template <class> class, bool> class dump_type> dumper::Field * createElementalField( const ElementTypeMapArray<T> & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem = ElementTypeMap<UInt>()); /// register an elemental field to the given group name (overloading for /// MaterialInternalField) template <typename T, /// type of InternalMaterialField template <typename, bool filtered> class dump_type> dumper::Field * createElementalField(const ElementTypeMapArray<T> & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem); template <typename type, bool flag, template <class, bool> class ftype> dumper::Field * createNodalField(const ftype<type, flag> * field, const std::string & group_name, UInt padding_size = 0); template <typename type, bool flag, template <class, bool> class ftype> dumper::Field * createStridedNodalField(const ftype<type, flag> * field, const std::string & group_name, UInt size, UInt stride, UInt padding_size); protected: /// fill a buffer with all the group names void fillBufferWithGroupNames( CommunicationBufferTemplated<false> & comm_buffer) const; /// take a buffer and create the missing groups localy void checkAndAddGroups(CommunicationBufferTemplated<true> & buffer); /// register an elemental field to the given group name template <class dump_type, typename field_type> inline dumper::Field * createElementalField(const field_type & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, const ElementTypeMap<UInt> & nb_data_per_elem); /// register an elemental field to the given group name template <class dump_type, typename field_type> inline dumper::Field * createElementalFilteredField(const field_type & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem); #endif /* ------------------------------------------------------------------------ */ /* Accessor */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(ElementGroups, element_groups, const ElementGroups &); const ElementGroup & getElementGroup(const std::string & name) const; const NodeGroup & getNodeGroup(const std::string & name) const; ElementGroup & getElementGroup(const std::string & name); NodeGroup & getNodeGroup(const std::string & name); UInt getNbElementGroups(UInt dimension = _all_dimensions) const; UInt getNbNodeGroups() { return node_groups.size(); }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id to create element and node groups ID id; /// memory_id to create element and node groups MemoryID memory_id; /// list of the node groups managed NodeGroups node_groups; /// list of the element groups managed ElementGroups element_groups; /// Mesh to which the element belongs const Mesh & mesh; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const GroupManager & _this) { _this.printself(stream); return stream; } } // namespace akantu #endif /* __AKANTU_GROUP_MANAGER_HH__ */ diff --git a/src/mesh/group_manager_inline_impl.cc b/src/mesh/group_manager_inline_impl.cc index 9629a5279..bfb9d0f6a 100644 --- a/src/mesh/group_manager_inline_impl.cc +++ b/src/mesh/group_manager_inline_impl.cc @@ -1,205 +1,205 @@ /** * @file group_manager_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Stores information relevent to the notion of domain boundary and * surfaces. * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_field.hh" #include "element_group.hh" #include "element_type_map_filter.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_nodal_field.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T, template <bool> class dump_type> dumper::Field * GroupManager::createElementalField( const ElementTypeMapArray<T> & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem) { const ElementTypeMapArray<T> * field_ptr = &field; if (field_ptr == nullptr) return nullptr; if (group_name == "all") return this->createElementalField<dump_type<false>>( field, group_name, spatial_dimension, kind, nb_data_per_elem); else return this->createElementalFilteredField<dump_type<true>>( field, group_name, spatial_dimension, kind, nb_data_per_elem); } /* -------------------------------------------------------------------------- */ template <typename T, template <class> class T2, template <class, template <class> class, bool> class dump_type> dumper::Field * GroupManager::createElementalField( const ElementTypeMapArray<T> & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem) { const ElementTypeMapArray<T> * field_ptr = &field; if (field_ptr == nullptr) return nullptr; if (group_name == "all") return this->createElementalField<dump_type<T, T2, false>>( field, group_name, spatial_dimension, kind, nb_data_per_elem); else return this->createElementalFilteredField<dump_type<T, T2, true>>( field, group_name, spatial_dimension, kind, nb_data_per_elem); } /* -------------------------------------------------------------------------- */ template <typename T, template <typename T2, bool filtered> class dump_type> ///< type of InternalMaterialField dumper::Field * GroupManager::createElementalField(const ElementTypeMapArray<T> & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem) { const ElementTypeMapArray<T> * field_ptr = &field; if (field_ptr == nullptr) return nullptr; if (group_name == "all") return this->createElementalField<dump_type<T, false>>( field, group_name, spatial_dimension, kind, nb_data_per_elem); else return this->createElementalFilteredField<dump_type<T, true>>( field, group_name, spatial_dimension, kind, nb_data_per_elem); } /* -------------------------------------------------------------------------- */ template <typename dump_type, typename field_type> dumper::Field * GroupManager::createElementalField( const field_type & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, const ElementTypeMap<UInt> & nb_data_per_elem) { const field_type * field_ptr = &field; if (field_ptr == nullptr) return nullptr; if (group_name != "all") throw; dumper::Field * dumper = new dump_type(field, spatial_dimension, _not_ghost, kind); dumper->setNbDataPerElem(nb_data_per_elem); return dumper; } /* -------------------------------------------------------------------------- */ template <typename dump_type, typename field_type> dumper::Field * GroupManager::createElementalFilteredField( const field_type & field, const std::string & group_name, UInt spatial_dimension, const ElementKind & kind, ElementTypeMap<UInt> nb_data_per_elem) { const field_type * field_ptr = &field; if (field_ptr == nullptr) return nullptr; if (group_name == "all") throw; using T = typename field_type::type; ElementGroup & group = this->getElementGroup(group_name); UInt dim = group.getDimension(); if (dim != spatial_dimension) throw; const ElementTypeMapArray<UInt> & elemental_filter = group.getElements(); auto * filtered = new ElementTypeMapArrayFilter<T>(field, elemental_filter, nb_data_per_elem); dumper::Field * dumper = new dump_type(*filtered, dim, _not_ghost, kind); dumper->setNbDataPerElem(nb_data_per_elem); return dumper; } /* -------------------------------------------------------------------------- */ template <typename type, bool flag, template <class, bool> class ftype> dumper::Field * GroupManager::createNodalField(const ftype<type, flag> * field, const std::string & group_name, UInt padding_size) { if (field == nullptr) return nullptr; if (group_name == "all") { using DumpType = typename dumper::NodalField<type, false>; auto * dumper = new DumpType(*field, 0, 0, nullptr); dumper->setPadding(padding_size); return dumper; } else { ElementGroup & group = this->getElementGroup(group_name); const Array<UInt> * nodal_filter = &(group.getNodes()); using DumpType = typename dumper::NodalField<type, true>; auto * dumper = new DumpType(*field, 0, 0, nodal_filter); dumper->setPadding(padding_size); return dumper; } return nullptr; } /* -------------------------------------------------------------------------- */ template <typename type, bool flag, template <class, bool> class ftype> dumper::Field * GroupManager::createStridedNodalField(const ftype<type, flag> * field, const std::string & group_name, UInt size, UInt stride, UInt padding_size) { if (field == NULL) return nullptr; if (group_name == "all") { using DumpType = typename dumper::NodalField<type, false>; auto * dumper = new DumpType(*field, size, stride, NULL); dumper->setPadding(padding_size); return dumper; } else { ElementGroup & group = this->getElementGroup(group_name); const Array<UInt> * nodal_filter = &(group.getNodes()); using DumpType = typename dumper::NodalField<type, true>; auto * dumper = new DumpType(*field, size, stride, nodal_filter); dumper->setPadding(padding_size); return dumper; } return nullptr; } /* -------------------------------------------------------------------------- */ } // namespace akantu #endif diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc index bb13d8b62..cc63c5fd2 100644 --- a/src/mesh/mesh.cc +++ b/src/mesh/mesh.cc @@ -1,570 +1,569 @@ /** * @file mesh.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Tue Feb 20 2018 * * @brief class handling meshes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_config.hh" /* -------------------------------------------------------------------------- */ #include "element_class.hh" #include "group_manager_inline_impl.cc" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_iterators.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "element_synchronizer.hh" #include "facet_synchronizer.hh" #include "mesh_utils_distribution.hh" #include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumper_field.hh" #include "dumper_internal_material_field.hh" #endif /* -------------------------------------------------------------------------- */ #include <limits> #include <sstream> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id, Communicator & communicator) : Memory(id, memory_id), GroupManager(*this, id + ":group_manager", memory_id), nodes_type(0, 1, id + ":nodes_type"), connectivities("connectivities", id, memory_id), ghosts_counters("ghosts_counters", id, memory_id), normals("normals", id, memory_id), spatial_dimension(spatial_dimension), lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.), size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.), local_upper_bounds(spatial_dimension, 0.), mesh_data("mesh_data", id, memory_id), communicator(&communicator) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, Communicator & communicator, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, communicator) { AKANTU_DEBUG_IN(); this->nodes = std::make_shared<Array<Real>>(0, spatial_dimension, id + ":coordinates"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, Communicator::getStaticCommunicator(), id, memory_id) {} /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const std::shared_ptr<Array<Real>> & nodes, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, Communicator::getStaticCommunicator()) { this->nodes = nodes; this->nb_global_nodes = this->nodes->size(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique<std::set<Element>>(); } this->computeBoundingBox(); } /* -------------------------------------------------------------------------- */ void Mesh::getBarycenters(Array<Real> & barycenter, const ElementType & type, const GhostType & ghost_type) const { barycenter.resize(getNbElement(type, ghost_type)); for (auto && data : enumerate(make_view(barycenter, spatial_dimension))) { getBarycenter(Element{type, UInt(std::get<0>(data)), ghost_type}, std::get<1>(data)); } } /* -------------------------------------------------------------------------- */ Mesh & Mesh::initMeshFacets(const ID & id) { AKANTU_DEBUG_IN(); if (!mesh_facets) { mesh_facets = std::make_unique<Mesh>(spatial_dimension, this->nodes, getID() + ":" + id, getMemoryID()); mesh_facets->mesh_parent = this; mesh_facets->is_mesh_facets = true; MeshUtils::buildAllFacets(*this, *mesh_facets, 0); if (mesh.isDistributed()) { mesh_facets->is_distributed = true; mesh_facets->element_synchronizer = std::make_unique<FacetSynchronizer>( *mesh_facets, mesh.getElementSynchronizer()); } /// transfers the the mesh physical names to the mesh facets if (not this->hasData("physical_names")) { AKANTU_DEBUG_OUT(); return *mesh_facets; } if (not mesh_facets->hasData("physical_names")) { mesh_facets->registerData<std::string>("physical_names"); } auto & mesh_phys_data = this->getData<std::string>("physical_names"); auto & phys_data = mesh_facets->getData<std::string>("physical_names"); phys_data.initialize(*mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true); ElementTypeMapArray<Real> barycenters(getID(), "temporary_barycenters"); barycenters.initialize(*mesh_facets, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true); for (auto && ghost_type : ghost_types) { for (auto && type : barycenters.elementTypes(spatial_dimension - 1, ghost_type)) { mesh_facets->getBarycenters(barycenters(type, ghost_type), type, ghost_type); } } for_each_element( mesh, [&](auto && element) { Vector<Real> barycenter(spatial_dimension); mesh.getBarycenter(element, barycenter); auto norm_barycenter = barycenter.norm(); auto tolerance = Math::getTolerance(); if (norm_barycenter > tolerance) tolerance *= norm_barycenter; const auto & element_to_facet = mesh_facets->getElementToSubelement( element.type, element.ghost_type); Vector<Real> barycenter_facet(spatial_dimension); auto range = enumerate(make_view(barycenters(element.type, element.ghost_type), spatial_dimension)); #ifndef AKANTU_NDEBUG auto min_dist = std::numeric_limits<Real>::max(); #endif // this is a spacial search coded the most inefficient way. auto facet = std::find_if(range.begin(), range.end(), [&](auto && data) { auto facet = std::get<0>(data); if (element_to_facet(facet)[1] == ElementNull) return false; auto norm_distance = barycenter.distance(std::get<1>(data)); #ifndef AKANTU_NDEBUG min_dist = std::min(min_dist, norm_distance); #endif return (norm_distance < tolerance); }); if (facet == range.end()) { AKANTU_DEBUG_INFO("The element " << element << " did not find its associated facet in the " "mesh_facets! Try to decrease math tolerance. " "The closest element was at a distance of " << min_dist); return; } // set physical name phys_data(Element{element.type, UInt(std::get<0>(*facet)), element.ghost_type}) = mesh_phys_data(element); }, _spatial_dimension = spatial_dimension - 1); mesh_facets->createGroupsFromMeshData<std::string>("physical_names"); } AKANTU_DEBUG_OUT(); return *mesh_facets; } /* -------------------------------------------------------------------------- */ void Mesh::defineMeshParent(const Mesh & mesh) { AKANTU_DEBUG_IN(); this->mesh_parent = &mesh; this->is_mesh_facets = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::~Mesh() = default; /* -------------------------------------------------------------------------- */ void Mesh::read(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.read(filename, *this, mesh_io_type); type_iterator it = this->firstType(spatial_dimension, _not_ghost, _ek_not_defined); type_iterator last = this->lastType(spatial_dimension, _not_ghost, _ek_not_defined); if (it == last) AKANTU_EXCEPTION( "The mesh contained in the file " << filename << " does not seem to be of the good dimension." << " No element of dimension " << spatial_dimension << " where read."); this->nb_global_nodes = this->nodes->size(); this->computeBoundingBox(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique<std::set<Element>>(); } } /* -------------------------------------------------------------------------- */ void Mesh::write(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.write(filename, *this, mesh_io_type); } /* -------------------------------------------------------------------------- */ void Mesh::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Mesh [" << std::endl; stream << space << " + id : " << getID() << std::endl; stream << space << " + spatial dimension : " << this->spatial_dimension << std::endl; stream << space << " + nodes [" << std::endl; nodes->printself(stream, indent + 2); stream << space << " + connectivities [" << std::endl; connectivities.printself(stream, indent + 2); stream << space << " ]" << std::endl; GroupManager::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void Mesh::computeBoundingBox() { AKANTU_DEBUG_IN(); for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::numeric_limits<double>::max(); local_upper_bounds(k) = -std::numeric_limits<double>::max(); } for (UInt i = 0; i < nodes->size(); ++i) { // if(!isPureGhostNode(i)) for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::min(local_lower_bounds[k], (*nodes)(i, k)); local_upper_bounds(k) = std::max(local_upper_bounds[k], (*nodes)(i, k)); } } if (this->is_distributed) { Matrix<Real> reduce_bounds(spatial_dimension, 2); for (UInt k = 0; k < spatial_dimension; ++k) { reduce_bounds(k, 0) = local_lower_bounds(k); reduce_bounds(k, 1) = -local_upper_bounds(k); } communicator->allReduce(reduce_bounds, SynchronizerOperation::_min); for (UInt k = 0; k < spatial_dimension; ++k) { lower_bounds(k) = reduce_bounds(k, 0); upper_bounds(k) = -reduce_bounds(k, 1); } } else { this->lower_bounds = this->local_lower_bounds; this->upper_bounds = this->local_upper_bounds; } size = upper_bounds - lower_bounds; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::initNormals() { normals.initialize(*this, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined); } /* -------------------------------------------------------------------------- */ void Mesh::getGlobalConnectivity( ElementTypeMapArray<UInt> & global_connectivity) { AKANTU_DEBUG_IN(); for (auto && ghost_type : ghost_types) { for (auto type : global_connectivity.elementTypes(_spatial_dimension = _all_dimensions, _element_kind = _ek_not_defined, _ghost_type = ghost_type)) { if (not connectivities.exists(type, ghost_type)) continue; auto & local_conn = connectivities(type, ghost_type); auto & g_connectivity = global_connectivity(type, ghost_type); UInt nb_nodes = local_conn.size() * local_conn.getNbComponent(); if (not nodes_global_ids && is_mesh_facets) { std::transform( local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *mesh_parent->nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } else { std::transform(local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Mesh::getGroupDumper(const std::string & dumper_name, const std::string & group_name) { if (group_name == "all") return this->getDumper(dumper_name); else return element_groups[group_name]->getDumper(dumper_name); } /* -------------------------------------------------------------------------- */ template <typename T> ElementTypeMap<UInt> Mesh::getNbDataPerElem(ElementTypeMapArray<T> & arrays, const ElementKind & element_kind) { ElementTypeMap<UInt> nb_data_per_elem; for (auto type : elementTypes(spatial_dimension, _not_ghost, element_kind)) { UInt nb_elements = this->getNbElement(type); auto & array = arrays(type); nb_data_per_elem(type) = array.getNbComponent() * array.size(); nb_data_per_elem(type) /= nb_elements; } return nb_data_per_elem; } /* -------------------------------------------------------------------------- */ template ElementTypeMap<UInt> Mesh::getNbDataPerElem(ElementTypeMapArray<Real> & array, const ElementKind & element_kind); template ElementTypeMap<UInt> Mesh::getNbDataPerElem(ElementTypeMapArray<UInt> & array, const ElementKind & element_kind); /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER template <typename T> dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind) { dumper::Field * field = nullptr; ElementTypeMapArray<T> * internal = nullptr; try { internal = &(this->getData<T>(field_id)); } catch (...) { return nullptr; } ElementTypeMap<UInt> nb_data_per_elem = this->getNbDataPerElem(*internal, element_kind); field = this->createElementalField<T, dumper::InternalMaterialField>( *internal, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); return field; } template dumper::Field * Mesh::createFieldFromAttachedData<Real>(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); template dumper::Field * Mesh::createFieldFromAttachedData<UInt>(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); #endif /* -------------------------------------------------------------------------- */ void Mesh::distribute() { this->distribute(Communicator::getStaticCommunicator()); } /* -------------------------------------------------------------------------- */ void Mesh::distribute(Communicator & communicator) { AKANTU_DEBUG_ASSERT(is_distributed == false, "This mesh is already distribute"); this->communicator = &communicator; this->element_synchronizer = std::make_unique<ElementSynchronizer>( *this, this->getID() + ":element_synchronizer", this->getMemoryID(), true); this->node_synchronizer = std::make_unique<NodeSynchronizer>( *this, this->getID() + ":node_synchronizer", this->getMemoryID(), true); Int psize = this->communicator->getNbProc(); #ifdef AKANTU_USE_SCOTCH Int prank = this->communicator->whoAmI(); if (prank == 0) { MeshPartitionScotch partition(*this, spatial_dimension); partition.partitionate(psize); MeshUtilsDistribution::distributeMeshCentralized(*this, 0, partition); } else { MeshUtilsDistribution::distributeMeshCentralized(*this, 0); } #else if (!(psize == 1)) { AKANTU_ERROR("Cannot distribute a mesh without a partitioning tool"); } #endif this->is_distributed = true; this->computeBoundingBox(); } /* -------------------------------------------------------------------------- */ void Mesh::getAssociatedElements(const Array<UInt> & node_list, Array<Element> & elements) { for (const auto & node : node_list) for (const auto & element : *nodes_to_elements[node]) elements.push_back(element); } /* -------------------------------------------------------------------------- */ void Mesh::fillNodesToElements() { Element e; UInt nb_nodes = nodes->size(); for (UInt n = 0; n < nb_nodes; ++n) { if (this->nodes_to_elements[n]) this->nodes_to_elements[n]->clear(); else this->nodes_to_elements[n] = std::make_unique<std::set<Element>>(); } for (auto ghost_type : ghost_types) { e.ghost_type = ghost_type; for (const auto & type : elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { e.type = type; UInt nb_element = this->getNbElement(type, ghost_type); Array<UInt>::const_iterator<Vector<UInt>> conn_it = connectivities(type, ghost_type) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; const Vector<UInt> & conn = *conn_it; for (UInt n = 0; n < conn.size(); ++n) nodes_to_elements[conn(n)]->insert(e); } } } } /* -------------------------------------------------------------------------- */ void Mesh::eraseElements(const Array<Element> & elements) { ElementTypeMap<UInt> last_element; RemovedElementsEvent event(*this); auto & remove_list = event.getList(); auto & new_numbering = event.getNewNumbering(); for (auto && el : elements) { if (el.ghost_type != _not_ghost) { auto & count = ghosts_counters(el); --count; if (count > 0) continue; } remove_list.push_back(el); if (not last_element.exists(el.type, el.ghost_type)) { UInt nb_element = mesh.getNbElement(el.type, el.ghost_type); last_element(nb_element - 1, el.type, el.ghost_type); auto & numbering = new_numbering.alloc(nb_element, 1, el.type, el.ghost_type); for (auto && pair : enumerate(numbering)) { std::get<1>(pair) = std::get<0>(pair); } } UInt & pos = last_element(el.type, el.ghost_type); auto & numbering = new_numbering(el.type, el.ghost_type); numbering(el.element) = UInt(-1); numbering(pos) = el.element; --pos; } this->sendEvent(event); } } // namespace akantu diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh index ffdd11510..c1d47f15e 100644 --- a/src/mesh/mesh.hh +++ b/src/mesh/mesh.hh @@ -1,613 +1,612 @@ /** * @file mesh.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Mon Feb 19 2018 * * @brief the class representing the meshes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_HH__ #define __AKANTU_MESH_HH__ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_event_handler_manager.hh" #include "aka_memory.hh" #include "dumpable.hh" #include "element.hh" #include "element_class.hh" #include "element_type_map.hh" #include "group_manager.hh" #include "mesh_data.hh" #include "mesh_events.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ namespace akantu { class Communicator; class ElementSynchronizer; class NodeSynchronizer; } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ /* Mesh */ /* -------------------------------------------------------------------------- */ /** * @class Mesh this contain the coordinates of the nodes in the Mesh.nodes * Array, and the connectivity. The connectivity are stored in by element * types. * * In order to loop on all element you have to loop on all types like this : * @code{.cpp} for(auto & type : mesh.elementTypes()) { UInt nb_element = mesh.getNbElement(type); const Array<UInt> & conn = mesh.getConnectivity(type); for(UInt e = 0; e < nb_element; ++e) { ... } } or for_each_element(mesh, [](Element & element) { std::cout << element << std::endl }); @endcode */ class Mesh : protected Memory, public EventHandlerManager<MeshEventHandler>, public GroupManager, public Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ private: /// default constructor used for chaining, the last parameter is just to /// differentiate constructors Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id, Communicator & communicator); public: /// constructor that create nodes coordinates array Mesh(UInt spatial_dimension, const ID & id = "mesh", const MemoryID & memory_id = 0); /// mesh not distributed and not using the default communicator Mesh(UInt spatial_dimension, Communicator & communicator, const ID & id = "mesh", const MemoryID & memory_id = 0); /// constructor that use an existing nodes coordinates array, by knowing its /// ID // Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, // const MemoryID & memory_id = 0); /** * constructor that use an existing nodes coordinates * array, by getting the vector of coordinates */ Mesh(UInt spatial_dimension, const std::shared_ptr<Array<Real>> & nodes, const ID & id = "mesh", const MemoryID & memory_id = 0); ~Mesh() override; /// @typedef ConnectivityTypeList list of the types present in a Mesh using ConnectivityTypeList = std::set<ElementType>; /// read the mesh from a file void read(const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); /// write the mesh to a file void write(const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); private: /// initialize the connectivity to NULL and other stuff void init(); /// function that computes the bounding box (fills xmin, xmax) void computeBoundingBox(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// patitionate the mesh among the processors involved in their computation virtual void distribute(Communicator & communicator); virtual void distribute(); /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; /// extract coordinates of nodes from an element template <typename T> inline void extractNodalValuesFromElement(const Array<T> & nodal_values, T * elemental_values, UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const; // /// extract coordinates of nodes from a reversed element // inline void extractNodalCoordinatesFromPBCElement(Real * local_coords, // UInt * connectivity, // UInt n_nodes); /// add a Array of connectivity for the type <type>. inline void addConnectivityType(const ElementType & type, const GhostType & ghost_type = _not_ghost); /* ------------------------------------------------------------------------ */ template <class Event> inline void sendEvent(Event & event) { // if(event.getList().size() != 0) EventHandlerManager<MeshEventHandler>::sendEvent<Event>(event); } /// prepare the event to remove the elements listed void eraseElements(const Array<Element> & elements); /* ------------------------------------------------------------------------ */ template <typename T> inline void removeNodesFromArray(Array<T> & vect, const Array<UInt> & new_numbering); /// initialize normals void initNormals(); /// init facets' mesh Mesh & initMeshFacets(const ID & id = "mesh_facets"); /// define parent mesh void defineMeshParent(const Mesh & mesh); /// get global connectivity array void getGlobalConnectivity(ElementTypeMapArray<UInt> & global_connectivity); public: void getAssociatedElements(const Array<UInt> & node_list, Array<Element> & elements); private: /// fills the nodes_to_elements structure void fillNodesToElements(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the id of the mesh AKANTU_GET_MACRO(ID, Memory::id, const ID &); /// get the id of the mesh AKANTU_GET_MACRO(MemoryID, Memory::memory_id, const MemoryID &); /// get the spatial dimension of the mesh = number of component of the /// coordinates AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the nodes Array aka coordinates AKANTU_GET_MACRO(Nodes, *nodes, const Array<Real> &); AKANTU_GET_MACRO_NOT_CONST(Nodes, *nodes, Array<Real> &); /// get the normals for the elements AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Normals, normals, Real); /// get the number of nodes AKANTU_GET_MACRO(NbNodes, nodes->size(), UInt); /// get the Array of global ids of the nodes (only used in parallel) AKANTU_GET_MACRO(GlobalNodesIds, *nodes_global_ids, const Array<UInt> &); AKANTU_GET_MACRO_NOT_CONST(GlobalNodesIds, *nodes_global_ids, Array<UInt> &); /// get the global id of a node inline UInt getNodeGlobalId(UInt local_id) const; /// get the global id of a node inline UInt getNodeLocalId(UInt global_id) const; /// get the global number of nodes inline UInt getNbGlobalNodes() const; /// get the nodes type Array AKANTU_GET_MACRO(NodesType, nodes_type, const Array<NodeType> &); protected: AKANTU_GET_MACRO_NOT_CONST(NodesType, nodes_type, Array<NodeType> &); public: inline NodeType getNodeType(UInt local_id) const; /// say if a node is a pure ghost node inline bool isPureGhostNode(UInt n) const; /// say if a node is pur local or master node inline bool isLocalOrMasterNode(UInt n) const; inline bool isLocalNode(UInt n) const; inline bool isMasterNode(UInt n) const; inline bool isSlaveNode(UInt n) const; AKANTU_GET_MACRO(LowerBounds, lower_bounds, const Vector<Real> &); AKANTU_GET_MACRO(UpperBounds, upper_bounds, const Vector<Real> &); AKANTU_GET_MACRO(LocalLowerBounds, local_lower_bounds, const Vector<Real> &); AKANTU_GET_MACRO(LocalUpperBounds, local_upper_bounds, const Vector<Real> &); /// get the connectivity Array for a given type AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Connectivity, connectivities, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Connectivity, connectivities, UInt); AKANTU_GET_MACRO(Connectivities, connectivities, const ElementTypeMapArray<UInt> &); /// get the number of element of a type in the mesh inline UInt getNbElement(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /// get the number of element for a given ghost_type and a given dimension inline UInt getNbElement(const UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & kind = _ek_not_defined) const; // /// get the connectivity list either for the elements or the ghost elements // inline const ConnectivityTypeList & // getConnectivityTypeList(const GhostType & ghost_type = _not_ghost) const; /// compute the barycenter of a given element private: inline void getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type = _not_ghost) const; public: inline void getBarycenter(const Element & element, Vector<Real> & barycenter) const; void getBarycenters(Array<Real> & barycenter, const ElementType & type, const GhostType & ghost_type) const; #ifndef SWIG /// get the element connected to a subelement const auto & getElementToSubelement() const; /// get the element connected to a subelement const auto & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the element connected to a subelement auto & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get the subelement connected to an element const auto & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the subelement connected to an element auto & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); #endif /// register a new ElementalTypeMap in the MeshData template <typename T> inline ElementTypeMapArray<T> & registerData(const std::string & data_name); template <typename T> inline bool hasData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template <typename T> inline const Array<T> & getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template <typename T> inline Array<T> & getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// tells if the data data_name is contained in the mesh or not inline bool hasData(const ID & data_name) const; /// get a name field associated to the mesh template <typename T> inline const ElementTypeMapArray<T> & getData(const ID & data_name) const; /// get a name field associated to the mesh template <typename T> inline ElementTypeMapArray<T> & getData(const ID & data_name); template <typename T> ElementTypeMap<UInt> getNbDataPerElem(ElementTypeMapArray<T> & array, const ElementKind & element_kind); template <typename T> dumper::Field * createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); /// templated getter returning the pointer to data in MeshData (modifiable) template <typename T> inline Array<T> & getDataPointer(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost, UInt nb_component = 1, bool size_to_nb_element = true, bool resize_with_parent = false); /// Facets mesh accessor inline const Mesh & getMeshFacets() const; inline Mesh & getMeshFacets(); /// Parent mesh accessor inline const Mesh & getMeshParent() const; inline bool isMeshFacets() const { return this->is_mesh_facets; } /// defines is the mesh is distributed or not inline bool isDistributed() const { return this->is_distributed; } #ifndef SWIG /// return the dumper from a group and and a dumper name DumperIOHelper & getGroupDumper(const std::string & dumper_name, const std::string & group_name); #endif /* ------------------------------------------------------------------------ */ /* Wrappers on ElementClass functions */ /* ------------------------------------------------------------------------ */ public: /// get the number of nodes per element for a given element type static inline UInt getNbNodesPerElement(const ElementType & type); /// get the number of nodes per element for a given element type considered as /// a first order element static inline ElementType getP1ElementType(const ElementType & type); /// get the kind of the element type static inline ElementKind getKind(const ElementType & type); /// get spatial dimension of a type of element static inline UInt getSpatialDimension(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type, UInt t); #ifndef SWIG /// get local connectivity of a facet for a given facet type static inline auto getFacetLocalConnectivity(const ElementType & type, UInt t = 0); /// get connectivity of facets for a given element inline auto getFacetConnectivity(const Element & element, UInt t = 0) const; #endif /// get the number of type of the surface element associated to a given /// element type static inline UInt getNbFacetTypes(const ElementType & type, UInt t = 0); #ifndef SWIG /// get the type of the surface element associated to a given element static inline constexpr auto getFacetType(const ElementType & type, UInt t = 0); /// get all the type of the surface element associated to a given element static inline constexpr auto getAllFacetTypes(const ElementType & type); #endif /// get the number of nodes in the given element list static inline UInt getNbNodesPerElementList(const Array<Element> & elements); /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ using type_iterator = ElementTypeMapArray<UInt, ElementType>::type_iterator; using ElementTypesIteratorHelper = ElementTypeMapArray<UInt, ElementType>::ElementTypesIteratorHelper; template <typename... pack> ElementTypesIteratorHelper elementTypes(pack &&... _pack) const; inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.firstType(dim, ghost_type, kind); } inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.lastType(dim, ghost_type, kind); } AKANTU_GET_MACRO(ElementSynchronizer, *element_synchronizer, const ElementSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(ElementSynchronizer, *element_synchronizer, ElementSynchronizer &); AKANTU_GET_MACRO(NodeSynchronizer, *node_synchronizer, const NodeSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(NodeSynchronizer, *node_synchronizer, NodeSynchronizer &); // AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, StaticCommunicator // &); #ifndef SWIG AKANTU_GET_MACRO(Communicator, *communicator, const auto &); AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, auto &); #endif /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshAccessor; AKANTU_GET_MACRO(NodesPointer, *nodes, Array<Real> &); /// get a pointer to the nodes_global_ids Array<UInt> and create it if /// necessary inline Array<UInt> & getNodesGlobalIdsPointer(); /// get a pointer to the nodes_type Array<Int> and create it if necessary inline Array<NodeType> & getNodesTypePointer(); /// get a pointer to the connectivity Array for the given type and create it /// if necessary inline Array<UInt> & getConnectivityPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get the ghost element counter inline Array<UInt> & getGhostsCounters(const ElementType & type, const GhostType & ghost_type = _ghost) { AKANTU_DEBUG_ASSERT(ghost_type != _not_ghost, "No ghost counter for _not_ghost elements"); return ghosts_counters(type, ghost_type); } /// get a pointer to the element_to_subelement Array for the given type and /// create it if necessary inline Array<std::vector<Element>> & getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get a pointer to the subelement_to_element Array for the given type and /// create it if necessary inline Array<Element> & getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); AKANTU_GET_MACRO_NOT_CONST(MeshData, mesh_data, MeshData &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// array of the nodes coordinates std::shared_ptr<Array<Real>> nodes; /// global node ids std::unique_ptr<Array<UInt>> nodes_global_ids; /// node type, -3 pure ghost, -2 master for the node, -1 normal node, i in /// [0-N] slave node and master is proc i Array<NodeType> nodes_type; /// global number of nodes; UInt nb_global_nodes{0}; /// all class of elements present in this mesh (for heterogenous meshes) ElementTypeMapArray<UInt> connectivities; /// count the references on ghost elements ElementTypeMapArray<UInt> ghosts_counters; /// map to normals for all class of elements present in this mesh ElementTypeMapArray<Real> normals; /// list of all existing types in the mesh // ConnectivityTypeList type_set; /// the spatial dimension of this mesh UInt spatial_dimension{0}; /// types offsets // Array<UInt> types_offsets; // /// list of all existing types in the mesh // ConnectivityTypeList ghost_type_set; // /// ghost types offsets // Array<UInt> ghost_types_offsets; /// min of coordinates Vector<Real> lower_bounds; /// max of coordinates Vector<Real> upper_bounds; /// size covered by the mesh on each direction Vector<Real> size; /// local min of coordinates Vector<Real> local_lower_bounds; /// local max of coordinates Vector<Real> local_upper_bounds; /// Extra data loaded from the mesh file MeshData mesh_data; /// facets' mesh std::unique_ptr<Mesh> mesh_facets; /// parent mesh (this is set for mesh_facets meshes) const Mesh * mesh_parent{nullptr}; /// defines if current mesh is mesh_facets or not bool is_mesh_facets{false}; /// defines if the mesh is centralized or distributed bool is_distributed{false}; /// Communicator on which mesh is distributed Communicator * communicator; /// Element synchronizer std::unique_ptr<ElementSynchronizer> element_synchronizer; /// Node synchronizer std::unique_ptr<NodeSynchronizer> node_synchronizer; using NodesToElements = std::vector<std::unique_ptr<std::set<Element>>>; /// This info is stored to simplify the dynamic changes NodesToElements nodes_to_elements; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Mesh & _this) { _this.printself(stream); return stream; } } // namespace akantu /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ #include "element_type_map_tmpl.hh" #include "mesh_inline_impl.cc" #endif /* __AKANTU_MESH_HH__ */ diff --git a/src/mesh/mesh_accessor.hh b/src/mesh/mesh_accessor.hh index 402286b60..9ac501700 100644 --- a/src/mesh/mesh_accessor.hh +++ b/src/mesh/mesh_accessor.hh @@ -1,135 +1,137 @@ /** * @file mesh_accessor.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jun 30 2015 + * @date last modification: Tue Sep 19 2017 * * @brief this class allow to access some private member of mesh it is used for * IO for examples * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_ACCESSOR_HH__ #define __AKANTU_MESH_ACCESSOR_HH__ namespace akantu { class NodeSynchronizer; class ElementSynchronizer; } // namespace akantu namespace akantu { class MeshAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit MeshAccessor(Mesh & mesh) : _mesh(mesh) {} virtual ~MeshAccessor() = default; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the global number of nodes inline UInt getNbGlobalNodes() const { return this->_mesh.nb_global_nodes; } /// set the global number of nodes inline void setNbGlobalNodes(UInt nb_global_nodes) { this->_mesh.nb_global_nodes = nb_global_nodes; } /// set the mesh as being distributed inline void setDistributed() { this->_mesh.is_distributed = true; } /// get a pointer to the nodes_global_ids Array<UInt> and create it if /// necessary inline auto & getNodesGlobalIds() { return this->_mesh.getNodesGlobalIdsPointer(); } /// get a pointer to the nodes_type Array<Int> and create it if necessary inline auto & getNodesType() { return this->_mesh.getNodesTypePointer(); } /// get a pointer to the coordinates Array inline auto & getNodes() { return this->_mesh.getNodesPointer(); } /// get a pointer to the coordinates Array inline auto getNodesSharedPtr() { return this->_mesh.nodes; } /// get a pointer to the connectivity Array for the given type and create it /// if necessary inline auto & getConnectivity(const ElementType & type, const GhostType & ghost_type = _not_ghost) { return this->_mesh.getConnectivityPointer(type, ghost_type); } /// get the ghost element counter inline auto & getGhostsCounters(const ElementType & type, const GhostType & ghost_type = _ghost) { return this->_mesh.getGhostsCounters(type, ghost_type); } /// get a pointer to the element_to_subelement Array for the given type and /// create it if necessary inline auto & getElementToSubelement(const ElementType & type, const GhostType & ghost_type = _not_ghost) { return this->_mesh.getElementToSubelementPointer(type, ghost_type); } /// get a pointer to the subelement_to_element Array for the given type and /// create it if necessary inline auto & getSubelementToElement(const ElementType & type, const GhostType & ghost_type = _not_ghost) { return this->_mesh.getSubelementToElementPointer(type, ghost_type); } template <typename T> inline auto & getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost, UInt nb_component = 1, bool size_to_nb_element = true, bool resize_with_parent = false) { return this->_mesh.getDataPointer<T>(data_name, el_type, ghost_type, nb_component, size_to_nb_element, resize_with_parent); } auto & getMeshData() { return this->_mesh.getMeshData(); } /// get the node synchonizer auto & getNodeSynchronizer() { return *this->_mesh.node_synchronizer; } /// get the element synchonizer auto & getElementSynchronizer() { return *this->_mesh.element_synchronizer; } private: Mesh & _mesh; }; } // namespace akantu #endif /* __AKANTU_MESH_ACCESSOR_HH__ */ diff --git a/src/mesh/mesh_data.cc b/src/mesh/mesh_data.cc index 88022e988..ead9bcf7c 100644 --- a/src/mesh/mesh_data.cc +++ b/src/mesh/mesh_data.cc @@ -1,48 +1,47 @@ /** * @file mesh_data.cc * * @author Dana Christen <dana.christen@gmail.com> * * @date creation: Fri Apr 13 2012 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Mon Jun 19 2017 * * @brief Stores generic data loaded from the mesh file * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #include "mesh_data.hh" #include "mesh.hh" namespace akantu { MeshData::MeshData(const ID & _id, const ID & parent_id, const MemoryID & mem_id) : Memory(parent_id + ":" + _id, mem_id) {} MeshData::~MeshData() { ElementalDataMap::iterator it, end; for (it = elemental_data.begin(); it != elemental_data.end(); ++it) { delete it->second; } } } // akantu diff --git a/src/mesh/mesh_data.hh b/src/mesh/mesh_data.hh index 029af4fe9..45650efae 100644 --- a/src/mesh/mesh_data.hh +++ b/src/mesh/mesh_data.hh @@ -1,153 +1,153 @@ /** * @file mesh_data.hh * * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri May 03 2013 - * @date last modification: Thu Nov 05 2015 + * @date last modification: Mon Dec 18 2017 * * @brief Stores generic data loaded from the mesh file * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_DATA_HH__ #define __AKANTU_MESH_DATA_HH__ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "element_type_map.hh" #include <map> #include <string> /* -------------------------------------------------------------------------- */ namespace akantu { #define AKANTU_MESH_DATA_TYPES \ ((_tc_int, Int))((_tc_uint, UInt))((_tc_real, Real))( \ (_tc_element, Element))((_tc_std_string, std::string))( \ (_tc_std_vector_element, std::vector<Element>)) #define AKANTU_MESH_DATA_TUPLE_FIRST_ELEM(s, data, elem) \ BOOST_PP_TUPLE_ELEM(2, 0, elem) enum MeshDataTypeCode : int { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(AKANTU_MESH_DATA_TUPLE_FIRST_ELEM, , AKANTU_MESH_DATA_TYPES)), _tc_unknown }; class MeshData : public Memory { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ private: using TypeCode = MeshDataTypeCode; using ElementalDataMap = std::map<std::string, ElementTypeMapBase *>; using StringVector = std::vector<std::string>; using TypeCodeMap = std::map<std::string, TypeCode>; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshData(const ID & id = "mesh_data", const ID & parent_id = "", const MemoryID & memory_id = 0); ~MeshData() override; /* ------------------------------------------------------------------------ */ /* Methods and accessors */ /* ------------------------------------------------------------------------ */ public: /// Register new elemental data (and alloc data) with check if the name is /// new template <typename T> void registerElementalData(const ID & name); inline void registerElementalData(const ID & name, TypeCode type); /// tells if the given array exists template <typename T> bool hasDataArray(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// tells if the given data exists bool hasData(const ID & data_name) const; /// Get an existing elemental data array template <typename T> const Array<T> & getElementalDataArray(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; template <typename T> Array<T> & getElementalDataArray(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// Get an elemental data array, if it does not exist: allocate it template <typename T> Array<T> & getElementalDataArrayAlloc(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost, UInt nb_component = 1); /// get the names of the data stored in elemental_data inline void getTagNames(StringVector & tags, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /// get the type of the data stored in elemental_data template <typename T> TypeCode getTypeCode() const; inline TypeCode getTypeCode(const ID & name) const; template <typename T> inline UInt getNbComponentTemplated(const ID & name, const ElementType & el_type, const GhostType & ghost_type) const; inline UInt getNbComponent(const ID & name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// Get an existing elemental data template <typename T> const ElementTypeMapArray<T> & getElementalData(const ID & name) const; template <typename T> ElementTypeMapArray<T> & getElementalData(const ID & name); private: /// Register new elemental data (add alloc data) template <typename T> ElementTypeMapArray<T> * allocElementalData(const ID & name); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// Map when elemental data is stored as ElementTypeMap ElementalDataMap elemental_data; /// Map when elementalType of the data stored in elemental_data TypeCodeMap typecode_map; }; } // akantu #include "mesh_data_tmpl.hh" #undef AKANTU_MESH_DATA_TUPLE_FIRST_ELEM #endif /* __AKANTU_MESH_DATA_HH__ */ diff --git a/src/mesh/mesh_data_tmpl.hh b/src/mesh/mesh_data_tmpl.hh index 6cd581045..7de088649 100644 --- a/src/mesh/mesh_data_tmpl.hh +++ b/src/mesh/mesh_data_tmpl.hh @@ -1,275 +1,276 @@ /** * @file mesh_data_tmpl.hh * * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri May 03 2013 - * @date last modification: Thu Nov 05 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Stores generic data loaded from the mesh file * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "mesh_data.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_DATA_TMPL_HH__ #define __AKANTU_MESH_DATA_TMPL_HH__ namespace akantu { #define MESH_DATA_GET_TYPE(r, data, type) \ template <> \ inline MeshDataTypeCode \ MeshData::getTypeCode<BOOST_PP_TUPLE_ELEM(2, 1, type)>() const { \ return BOOST_PP_TUPLE_ELEM(2, 0, type); \ } /* -------------------------------------------------------------------------- */ // get the type of the data stored in elemental_data template <typename T> inline MeshDataTypeCode MeshData::getTypeCode() const { AKANTU_ERROR("Type " << debug::demangle(typeid(T).name()) << "not implemented by MeshData."); } /* -------------------------------------------------------------------------- */ BOOST_PP_SEQ_FOR_EACH(MESH_DATA_GET_TYPE, void, AKANTU_MESH_DATA_TYPES) #undef MESH_DATA_GET_TYPE inline MeshDataTypeCode MeshData::getTypeCode(const ID & name) const { auto it = typecode_map.find(name); if (it == typecode_map.end()) AKANTU_EXCEPTION("No dataset named " << name << " found."); return it->second; } /* -------------------------------------------------------------------------- */ // Register new elemental data templated (and alloc data) with check if the // name is new template <typename T> void MeshData::registerElementalData(const ID & name) { auto it = elemental_data.find(name); if (it == elemental_data.end()) { allocElementalData<T>(name); } else { AKANTU_DEBUG_INFO("Data named " << name << " already registered."); } } /* -------------------------------------------------------------------------- */ // Register new elemental data of a given MeshDataTypeCode with check if the // name is new #define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ registerElementalData<BOOST_PP_TUPLE_ELEM(2, 1, elem)>(name); \ break; \ } inline void MeshData::registerElementalData(const ID & name, MeshDataTypeCode type) { switch (type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, name, AKANTU_MESH_DATA_TYPES) default: AKANTU_ERROR("Type " << type << "not implemented by MeshData."); } } #undef AKANTU_MESH_DATA_CASE_MACRO /* -------------------------------------------------------------------------- */ /// Register new elemental data (and alloc data) template <typename T> ElementTypeMapArray<T> * MeshData::allocElementalData(const ID & name) { auto * dataset = new ElementTypeMapArray<T>(name, id, memory_id); elemental_data[name] = dataset; typecode_map[name] = getTypeCode<T>(); return dataset; } /* -------------------------------------------------------------------------- */ template <typename T> const ElementTypeMapArray<T> & MeshData::getElementalData(const ID & name) const { auto it = elemental_data.find(name); if (it == elemental_data.end()) AKANTU_EXCEPTION("No dataset named " << name << " found."); return dynamic_cast<const ElementTypeMapArray<T> &>(*(it->second)); } /* -------------------------------------------------------------------------- */ // Get an existing elemental data template <typename T> ElementTypeMapArray<T> & MeshData::getElementalData(const ID & name) { auto it = elemental_data.find(name); if (it == elemental_data.end()) AKANTU_EXCEPTION("No dataset named " << name << " found."); return dynamic_cast<ElementTypeMapArray<T> &>(*(it->second)); } /* -------------------------------------------------------------------------- */ template <typename T> bool MeshData::hasDataArray(const ID & name, const ElementType & elem_type, const GhostType & ghost_type) const { auto it = elemental_data.find(name); if (it == elemental_data.end()) return false; auto & elem_map = dynamic_cast<const ElementTypeMapArray<T> &>(*(it->second)); return elem_map.exists(elem_type, ghost_type); } /* -------------------------------------------------------------------------- */ inline bool MeshData::hasData(const ID & name) const { auto it = elemental_data.find(name); return (it != elemental_data.end()); } /* -------------------------------------------------------------------------- */ template <typename T> const Array<T> & MeshData::getElementalDataArray(const ID & name, const ElementType & elem_type, const GhostType & ghost_type) const { auto it = elemental_data.find(name); if (it == elemental_data.end()) { AKANTU_EXCEPTION("Data named " << name << " not registered for type: " << elem_type << " - ghost_type:" << ghost_type << "!"); } return dynamic_cast<const ElementTypeMapArray<T> &>(*(it->second))( elem_type, ghost_type); } template <typename T> Array<T> & MeshData::getElementalDataArray(const ID & name, const ElementType & elem_type, const GhostType & ghost_type) { auto it = elemental_data.find(name); if (it == elemental_data.end()) { AKANTU_EXCEPTION("Data named " << name << " not registered for type: " << elem_type << " - ghost_type:" << ghost_type << "!"); } return dynamic_cast<ElementTypeMapArray<T> &>(*(it->second))(elem_type, ghost_type); } /* -------------------------------------------------------------------------- */ // Get an elemental data array, if it does not exist: allocate it template <typename T> Array<T> & MeshData::getElementalDataArrayAlloc(const ID & name, const ElementType & elem_type, const GhostType & ghost_type, UInt nb_component) { auto it = elemental_data.find(name); ElementTypeMapArray<T> * dataset; if (it == elemental_data.end()) { dataset = allocElementalData<T>(name); } else { dataset = dynamic_cast<ElementTypeMapArray<T> *>(it->second); } AKANTU_DEBUG_ASSERT( getTypeCode<T>() == typecode_map.find(name)->second, "Function getElementalDataArrayAlloc called with the wrong type!"); if (!(dataset->exists(elem_type, ghost_type))) { dataset->alloc(0, nb_component, elem_type, ghost_type); } return (*dataset)(elem_type, ghost_type); } /* -------------------------------------------------------------------------- */ #define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ nb_comp = getNbComponentTemplated<BOOST_PP_TUPLE_ELEM(2, 1, elem)>( \ name, el_type, ghost_type); \ break; \ } inline UInt MeshData::getNbComponent(const ID & name, const ElementType & el_type, const GhostType & ghost_type) const { auto it = typecode_map.find(name); UInt nb_comp(0); if (it == typecode_map.end()) { AKANTU_EXCEPTION("Could not determine the type held in dataset " << name << " for type: " << el_type << " - ghost_type:" << ghost_type << "."); } MeshDataTypeCode type = it->second; switch (type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, name, AKANTU_MESH_DATA_TYPES) default: AKANTU_ERROR( "Could not call the correct instance of getNbComponentTemplated."); break; } return nb_comp; } #undef AKANTU_MESH_DATA_CASE_MACRO /* -------------------------------------------------------------------------- */ template <typename T> inline UInt MeshData::getNbComponentTemplated(const ID & name, const ElementType & el_type, const GhostType & ghost_type) const { return getElementalDataArray<T>(name, el_type, ghost_type).getNbComponent(); } /* -------------------------------------------------------------------------- */ // get the names of the data stored in elemental_data #define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ ElementTypeMapArray<BOOST_PP_TUPLE_ELEM(2, 1, elem)> * dataset; \ dataset = \ dynamic_cast<ElementTypeMapArray<BOOST_PP_TUPLE_ELEM(2, 1, elem)> *>( \ it->second); \ exists = dataset->exists(el_type, ghost_type); \ break; \ } inline void MeshData::getTagNames(StringVector & tags, const ElementType & el_type, const GhostType & ghost_type) const { tags.clear(); bool exists(false); auto it = elemental_data.begin(); auto it_end = elemental_data.end(); for (; it != it_end; ++it) { MeshDataTypeCode type = getTypeCode(it->first); switch (type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, , AKANTU_MESH_DATA_TYPES) default: AKANTU_ERROR("Could not determine the proper type to (dynamic-)cast."); break; } if (exists) { tags.push_back(it->first); } } } #undef AKANTU_MESH_DATA_CASE_MACRO /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_MESH_DATA_TMPL_HH__ */ diff --git a/src/mesh/mesh_events.hh b/src/mesh/mesh_events.hh index 53f8f0d9a..a654c4f5e 100644 --- a/src/mesh/mesh_events.hh +++ b/src/mesh/mesh_events.hh @@ -1,198 +1,198 @@ /** * @file mesh_events.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Feb 20 2015 - * @date last modification: Mon Dec 07 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Classes corresponding to mesh events type * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <utility> #include "aka_array.hh" #include "element.hh" #include "element_type_map.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_EVENTS_HH__ #define __AKANTU_MESH_EVENTS_HH__ namespace akantu { /// akantu::MeshEvent is the base event for meshes template <class Entity> class MeshEvent { public: virtual ~MeshEvent() = default; /// Get the list of entity modified by the event nodes or elements const Array<Entity> & getList() const { return list; } /// Get the list of entity modified by the event nodes or elements Array<Entity> & getList() { return list; } protected: Array<Entity> list; }; class Mesh; /// akantu::MeshEvent related to new nodes in the mesh class NewNodesEvent : public MeshEvent<UInt> { public: ~NewNodesEvent() override = default; }; /// akantu::MeshEvent related to nodes removed from the mesh class RemovedNodesEvent : public MeshEvent<UInt> { public: ~RemovedNodesEvent() override = default; inline RemovedNodesEvent(const Mesh & mesh); /// Get the new numbering following suppression of nodes from nodes arrays AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, Array<UInt> &); /// Get the new numbering following suppression of nodes from nodes arrays AKANTU_GET_MACRO(NewNumbering, new_numbering, const Array<UInt> &); private: Array<UInt> new_numbering; }; /// akantu::MeshEvent related to new elements in the mesh class NewElementsEvent : public MeshEvent<Element> { public: ~NewElementsEvent() override = default; }; /// akantu::MeshEvent related to elements removed from the mesh class RemovedElementsEvent : public MeshEvent<Element> { public: ~RemovedElementsEvent() override = default; inline RemovedElementsEvent(const Mesh & mesh, const ID & new_numbering_id = "new_numbering"); /// Get the new numbering following suppression of elements from elements /// arrays AKANTU_GET_MACRO(NewNumbering, new_numbering, const ElementTypeMapArray<UInt> &); /// Get the new numbering following suppression of elements from elements /// arrays AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, ElementTypeMapArray<UInt> &); /// Get the new numbering following suppression of elements from elements /// arrays AKANTU_GET_MACRO_BY_ELEMENT_TYPE(NewNumbering, new_numbering, UInt); /// Get the new numbering following suppression of elements from elements /// arrays AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(NewNumbering, new_numbering, UInt); protected: ElementTypeMapArray<UInt> new_numbering; }; /// akantu::MeshEvent for element that changed in some sort, can be seen as a /// combination of removed and added elements class ChangedElementsEvent : public RemovedElementsEvent { public: ~ChangedElementsEvent() override = default; inline ChangedElementsEvent( const Mesh & mesh, ID new_numbering_id = "changed_event:new_numbering") : RemovedElementsEvent(mesh, std::move(new_numbering_id)){}; AKANTU_GET_MACRO(ListOld, list, const Array<Element> &); AKANTU_GET_MACRO_NOT_CONST(ListOld, list, Array<Element> &); AKANTU_GET_MACRO(ListNew, new_list, const Array<Element> &); AKANTU_GET_MACRO_NOT_CONST(ListNew, new_list, Array<Element> &); protected: Array<Element> new_list; }; /* -------------------------------------------------------------------------- */ class MeshEventHandler { public: virtual ~MeshEventHandler() = default; /* ------------------------------------------------------------------------ */ /* Internal code */ /* ------------------------------------------------------------------------ */ private: /// send a akantu::NewNodesEvent inline void sendEvent(const NewNodesEvent & event) { onNodesAdded(event.getList(), event); } /// send a akantu::RemovedNodesEvent inline void sendEvent(const RemovedNodesEvent & event) { onNodesRemoved(event.getList(), event.getNewNumbering(), event); } /// send a akantu::NewElementsEvent inline void sendEvent(const NewElementsEvent & event) { onElementsAdded(event.getList(), event); } /// send a akantu::RemovedElementsEvent inline void sendEvent(const RemovedElementsEvent & event) { onElementsRemoved(event.getList(), event.getNewNumbering(), event); } /// send a akantu::ChangedElementsEvent inline void sendEvent(const ChangedElementsEvent & event) { onElementsChanged(event.getListOld(), event.getListNew(), event.getNewNumbering(), event); } template <class EventHandler> friend class EventHandlerManager; /* ------------------------------------------------------------------------ */ /* Interface */ /* ------------------------------------------------------------------------ */ public: /// function to implement to react on akantu::NewNodesEvent virtual void onNodesAdded(const Array<UInt> & /*nodes_list*/, const NewNodesEvent & /*event*/) { AKANTU_TO_IMPLEMENT(); } /// function to implement to react on akantu::RemovedNodesEvent virtual void onNodesRemoved(const Array<UInt> & /*nodes_list*/, const Array<UInt> & /*new_numbering*/, const RemovedNodesEvent & /*event*/) { AKANTU_TO_IMPLEMENT(); } /// function to implement to react on akantu::NewElementsEvent virtual void onElementsAdded(const Array<Element> & /*elements_list*/, const NewElementsEvent & /*event*/) { AKANTU_TO_IMPLEMENT(); } /// function to implement to react on akantu::RemovedElementsEvent virtual void onElementsRemoved(const Array<Element> & /*elements_list*/, const ElementTypeMapArray<UInt> & /*new_numbering*/, const RemovedElementsEvent & /*event*/) { AKANTU_TO_IMPLEMENT(); } /// function to implement to react on akantu::ChangedElementsEvent virtual void onElementsChanged(const Array<Element> & /*old_elements_list*/, const Array<Element> & /*new_elements_list*/, const ElementTypeMapArray<UInt> & /*new_numbering*/, const ChangedElementsEvent & /*event*/) { AKANTU_TO_IMPLEMENT(); } }; } // akantu #endif /* __AKANTU_MESH_EVENTS_HH__ */ diff --git a/src/mesh/mesh_filter.hh b/src/mesh/mesh_filter.hh index 59420e63d..3607f549d 100644 --- a/src/mesh/mesh_filter.hh +++ b/src/mesh/mesh_filter.hh @@ -1,73 +1,72 @@ /** * @file mesh_filter.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Dec 18 2015 + * @date last modification: Tue Feb 20 2018 * * @brief the class representing the meshes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_FILTER_HH__ #define __AKANTU_MESH_FILTER_HH__ /* -------------------------------------------------------------------------- */ #include "element.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* Filter Functors */ /* -------------------------------------------------------------------------- */ /// struct for the possible filter functors struct FilterFunctor { enum Type { _node_filter_functor, _element_filter_functor }; }; /// class (functor) for the node filter class NodeFilterFunctor : public FilterFunctor { public: bool operator()(__attribute__((unused)) UInt node) { AKANTU_TO_IMPLEMENT(); } public: static const Type type = _node_filter_functor; }; /// class (functor) for the element filter class ElementFilterFunctor : public FilterFunctor { public: bool operator()(__attribute__((unused)) const Element & element) { AKANTU_TO_IMPLEMENT(); } public: static const Type type = _element_filter_functor; }; } // akantu #endif /* __AKANTU_MESH_FILTER_HH__ */ diff --git a/src/mesh/mesh_inline_impl.cc b/src/mesh/mesh_inline_impl.cc index fd19d3982..2e4b756b5 100644 --- a/src/mesh/mesh_inline_impl.cc +++ b/src/mesh/mesh_inline_impl.cc @@ -1,637 +1,636 @@ /** * @file mesh_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Thu Jul 15 2010 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Mon Dec 18 2017 * * @brief Implementation of the inline functions of the mesh 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "element_class.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_INLINE_IMPL_CC__ #define __AKANTU_MESH_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ inline ElementKind Element::kind() const { return Mesh::getKind(type); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <typename... pack> Mesh::ElementTypesIteratorHelper Mesh::elementTypes(pack &&... _pack) const { return connectivities.elementTypes(_pack...); } /* -------------------------------------------------------------------------- */ inline RemovedNodesEvent::RemovedNodesEvent(const Mesh & mesh) : new_numbering(mesh.getNbNodes(), 1, "new_numbering") {} /* -------------------------------------------------------------------------- */ inline RemovedElementsEvent::RemovedElementsEvent(const Mesh & mesh, const ID & new_numbering_id) : new_numbering(new_numbering_id, mesh.getID(), mesh.getMemoryID()) {} /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent<NewElementsEvent>(NewElementsEvent & event) { this->nodes_to_elements.resize(nodes->size()); for (const auto & elem : event.getList()) { const Array<UInt> & conn = connectivities(elem.type, elem.ghost_type); UInt nb_nodes_per_elem = this->getNbNodesPerElement(elem.type); for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = conn(elem.element, n); if (not nodes_to_elements[node]) nodes_to_elements[node] = std::make_unique<std::set<Element>>(); nodes_to_elements[node]->insert(elem); } } EventHandlerManager<MeshEventHandler>::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent<NewNodesEvent>(NewNodesEvent & event) { this->computeBoundingBox(); EventHandlerManager<MeshEventHandler>::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent<RemovedElementsEvent>(RemovedElementsEvent & event) { this->connectivities.onElementsRemoved(event.getNewNumbering()); this->fillNodesToElements(); this->computeBoundingBox(); EventHandlerManager<MeshEventHandler>::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent<RemovedNodesEvent>(RemovedNodesEvent & event) { const auto & new_numbering = event.getNewNumbering(); this->removeNodesFromArray(*nodes, new_numbering); if (nodes_global_ids) this->removeNodesFromArray(*nodes_global_ids, new_numbering); if (nodes_type.size() != 0) this->removeNodesFromArray(nodes_type, new_numbering); if (not nodes_to_elements.empty()) { std::vector<std::unique_ptr<std::set<Element>>> tmp( nodes_to_elements.size()); auto it = nodes_to_elements.begin(); UInt new_nb_nodes = 0; for (auto new_i : new_numbering) { if (new_i != UInt(-1)) { tmp[new_i] = std::move(*it); ++new_nb_nodes; } ++it; } tmp.resize(new_nb_nodes); std::move(tmp.begin(), tmp.end(), nodes_to_elements.begin()); } computeBoundingBox(); EventHandlerManager<MeshEventHandler>::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Mesh::removeNodesFromArray(Array<T> & vect, const Array<UInt> & new_numbering) { Array<T> tmp(vect.size(), vect.getNbComponent()); UInt nb_component = vect.getNbComponent(); UInt new_nb_nodes = 0; for (UInt i = 0; i < new_numbering.size(); ++i) { UInt new_i = new_numbering(i); if (new_i != UInt(-1)) { T * to_copy = vect.storage() + i * nb_component; std::uninitialized_copy(to_copy, to_copy + nb_component, tmp.storage() + new_i * nb_component); ++new_nb_nodes; } } tmp.resize(new_nb_nodes); vect.copy(tmp); } /* -------------------------------------------------------------------------- */ inline Array<UInt> & Mesh::getNodesGlobalIdsPointer() { AKANTU_DEBUG_IN(); if (not nodes_global_ids) { nodes_global_ids = std::make_unique<Array<UInt>>( nodes->size(), 1, getID() + ":nodes_global_ids"); for (auto && global_ids : enumerate(*nodes_global_ids)) { std::get<1>(global_ids) = std::get<0>(global_ids); } } AKANTU_DEBUG_OUT(); return *nodes_global_ids; } /* -------------------------------------------------------------------------- */ inline Array<NodeType> & Mesh::getNodesTypePointer() { AKANTU_DEBUG_IN(); if (nodes_type.size() == 0) { nodes_type.resize(nodes->size()); nodes_type.set(_nt_normal); } AKANTU_DEBUG_OUT(); return nodes_type; } /* -------------------------------------------------------------------------- */ inline Array<UInt> & Mesh::getConnectivityPointer(const ElementType & type, const GhostType & ghost_type) { if (connectivities.exists(type, ghost_type)) return connectivities(type, ghost_type); if (ghost_type != _not_ghost) { ghosts_counters.alloc(0, 1, type, ghost_type, 1); } AKANTU_DEBUG_INFO("The connectivity vector for the type " << type << " created"); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); return connectivities.alloc(0, nb_nodes_per_element, type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array<std::vector<Element>> & Mesh::getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type) { return getDataPointer<std::vector<Element>>("element_to_subelement", type, ghost_type, 1, true); } /* -------------------------------------------------------------------------- */ inline Array<Element> & Mesh::getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type) { auto & array = getDataPointer<Element>( "subelement_to_element", type, ghost_type, getNbFacetsPerElement(type), true, is_mesh_facets); array.set(ElementNull); return array; } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getElementToSubelement() const { return getData<std::vector<Element>>("element_to_subelement"); } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) const { return getData<std::vector<Element>>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline auto & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) { return getData<std::vector<Element>>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getSubelementToElement(const ElementType & type, const GhostType & ghost_type) const { return getData<Element>("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline auto & Mesh::getSubelementToElement(const ElementType & type, const GhostType & ghost_type) { return getData<Element>("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ template <typename T> inline Array<T> & Mesh::getDataPointer(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type, UInt nb_component, bool size_to_nb_element, bool resize_with_parent) { Array<T> & tmp = mesh_data.getElementalDataArrayAlloc<T>( data_name, el_type, ghost_type, nb_component); if (size_to_nb_element) { if (resize_with_parent) tmp.resize(mesh_parent->getNbElement(el_type, ghost_type)); else tmp.resize(this->getNbElement(el_type, ghost_type)); } else { tmp.resize(0); } return tmp; } /* -------------------------------------------------------------------------- */ template <typename T> inline bool Mesh::hasData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type) const { return mesh_data.hasDataArray<T>(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template <typename T> inline const Array<T> & Mesh::getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type) const { return mesh_data.getElementalDataArray<T>(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template <typename T> inline Array<T> & Mesh::getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type) { return mesh_data.getElementalDataArray<T>(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ inline bool Mesh::hasData(const ID & data_name) const { return mesh_data.hasData(data_name); } /* -------------------------------------------------------------------------- */ template <typename T> inline const ElementTypeMapArray<T> & Mesh::getData(const ID & data_name) const { return mesh_data.getElementalData<T>(data_name); } /* -------------------------------------------------------------------------- */ template <typename T> inline ElementTypeMapArray<T> & Mesh::getData(const ID & data_name) { return mesh_data.getElementalData<T>(data_name); } /* -------------------------------------------------------------------------- */ template <typename T> inline ElementTypeMapArray<T> & Mesh::registerData(const ID & data_name) { this->mesh_data.registerElementalData<T>(data_name); return this->getData<T>(data_name); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const ElementType & type, const GhostType & ghost_type) const { try { const Array<UInt> & conn = connectivities(type, ghost_type); return conn.size(); } catch (...) { return 0; } } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & kind) const { AKANTU_DEBUG_ASSERT(spatial_dimension <= 3 || spatial_dimension == UInt(-1), "spatial_dimension is " << spatial_dimension << " and is greater than 3 !"); UInt nb_element = 0; for (auto type : elementTypes(spatial_dimension, ghost_type, kind)) nb_element += getNbElement(type, ghost_type); return nb_element; } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type) const { UInt * conn_val = getConnectivity(type, ghost_type).storage(); UInt nb_nodes_per_element = getNbNodesPerElement(type); auto * local_coord = new Real[spatial_dimension * nb_nodes_per_element]; UInt offset = element * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { memcpy(local_coord + n * spatial_dimension, nodes->storage() + conn_val[offset + n] * spatial_dimension, spatial_dimension * sizeof(Real)); } Math::barycenter(local_coord, nb_nodes_per_element, spatial_dimension, barycenter); delete[] local_coord; } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(const Element & element, Vector<Real> & barycenter) const { getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElement(const ElementType & type) { UInt nb_nodes_per_element = 0; #define GET_NB_NODES_PER_ELEMENT(type) \ nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_NODES_PER_ELEMENT); #undef GET_NB_NODES_PER_ELEMENT return nb_nodes_per_element; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getP1ElementType(const ElementType & type) { ElementType p1_type = _not_defined; #define GET_P1_TYPE(type) p1_type = ElementClass<type>::getP1ElementType() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_P1_TYPE); #undef GET_P1_TYPE return p1_type; } /* -------------------------------------------------------------------------- */ inline ElementKind Mesh::getKind(const ElementType & type) { ElementKind kind = _ek_not_defined; #define GET_KIND(type) kind = ElementClass<type>::getKind() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_KIND); #undef GET_KIND return kind; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getSpatialDimension(const ElementType & type) { UInt spatial_dimension = 0; #define GET_SPATIAL_DIMENSION(type) \ spatial_dimension = ElementClass<type>::getSpatialDimension() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SPATIAL_DIMENSION); #undef GET_SPATIAL_DIMENSION return spatial_dimension; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetTypes(const ElementType & type, __attribute__((unused)) UInt t) { UInt nb = 0; #define GET_NB_FACET_TYPE(type) nb = ElementClass<type>::getNbFacetTypes() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET_TYPE); #undef GET_NB_FACET_TYPE return nb; } /* -------------------------------------------------------------------------- */ inline constexpr auto Mesh::getFacetType(const ElementType & type, UInt t) { #define GET_FACET_TYPE(type) return ElementClass<type>::getFacetType(t); AKANTU_BOOST_ALL_ELEMENT_SWITCH_NO_DEFAULT(GET_FACET_TYPE); #undef GET_FACET_TYPE return _not_defined; } /* -------------------------------------------------------------------------- */ inline constexpr auto Mesh::getAllFacetTypes(const ElementType & type) { #define GET_FACET_TYPE(type) return ElementClass<type>::getFacetTypes(); AKANTU_BOOST_ALL_ELEMENT_SWITCH_NO_DEFAULT(GET_FACET_TYPE); #undef GET_FACET_TYPE return ElementClass<_not_defined>::getFacetTypes(); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(const ElementType & type) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) n_facet = ElementClass<type>::getNbFacetsPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(const ElementType & type, UInt t) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) \ n_facet = ElementClass<type>::getNbFacetsPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline auto Mesh::getFacetLocalConnectivity(const ElementType & type, UInt t) { AKANTU_DEBUG_IN(); #define GET_FACET_CON(type) \ AKANTU_DEBUG_OUT(); \ return ElementClass<type>::getFacetLocalConnectivityPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_CON); #undef GET_FACET_CON AKANTU_DEBUG_OUT(); return ElementClass<_not_defined>::getFacetLocalConnectivityPerElement(0); // This avoid a compilation warning but will certainly // also cause a segfault if reached } /* -------------------------------------------------------------------------- */ inline auto Mesh::getFacetConnectivity(const Element & element, UInt t) const { AKANTU_DEBUG_IN(); Matrix<const UInt> local_facets(getFacetLocalConnectivity(element.type, t)); Matrix<UInt> facets(local_facets.rows(), local_facets.cols()); const Array<UInt> & conn = connectivities(element.type, element.ghost_type); for (UInt f = 0; f < facets.rows(); ++f) { for (UInt n = 0; n < facets.cols(); ++n) { facets(f, n) = conn(element.element, local_facets(f, n)); } } AKANTU_DEBUG_OUT(); return facets; } /* -------------------------------------------------------------------------- */ template <typename T> inline void Mesh::extractNodalValuesFromElement( const Array<T> & nodal_values, T * local_coord, UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const { for (UInt n = 0; n < n_nodes; ++n) { memcpy(local_coord + n * nb_degree_of_freedom, nodal_values.storage() + connectivity[n] * nb_degree_of_freedom, nb_degree_of_freedom * sizeof(T)); } } /* -------------------------------------------------------------------------- */ inline void Mesh::addConnectivityType(const ElementType & type, const GhostType & ghost_type) { getConnectivityPointer(type, ghost_type); } /* -------------------------------------------------------------------------- */ inline bool Mesh::isPureGhostNode(UInt n) const { return nodes_type.size() ? (nodes_type(n) == _nt_pure_gost) : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalOrMasterNode(UInt n) const { return nodes_type.size() ? (nodes_type(n) == _nt_master) || (nodes_type(n) == _nt_normal) : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalNode(UInt n) const { return nodes_type.size() ? nodes_type(n) == _nt_normal : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isMasterNode(UInt n) const { return nodes_type.size() ? nodes_type(n) == _nt_master : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isSlaveNode(UInt n) const { return nodes_type.size() ? nodes_type(n) >= 0 : false; } /* -------------------------------------------------------------------------- */ inline NodeType Mesh::getNodeType(UInt local_id) const { return nodes_type.size() ? nodes_type(local_id) : _nt_normal; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeGlobalId(UInt local_id) const { return nodes_global_ids ? (*nodes_global_ids)(local_id) : local_id; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeLocalId(UInt global_id) const { AKANTU_DEBUG_ASSERT(nodes_global_ids != nullptr, "The global ids are note set."); return nodes_global_ids->find(global_id); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbGlobalNodes() const { return nodes_global_ids ? nb_global_nodes : nodes->size(); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElementList(const Array<Element> & elements) { UInt nb_nodes_per_element = 0; UInt nb_nodes = 0; ElementType current_element_type = _not_defined; Array<Element>::const_iterator<Element> el_it = elements.begin(); Array<Element>::const_iterator<Element> el_end = elements.end(); for (; el_it != el_end; ++el_it) { const Element & el = *el_it; if (el.type != current_element_type) { current_element_type = el.type; nb_nodes_per_element = Mesh::getNbNodesPerElement(current_element_type); } nb_nodes += nb_nodes_per_element; } return nb_nodes; } /* -------------------------------------------------------------------------- */ inline Mesh & Mesh::getMeshFacets() { if (!this->mesh_facets) AKANTU_SILENT_EXCEPTION( "No facet mesh is defined yet! check the buildFacets functions"); return *this->mesh_facets; } /* -------------------------------------------------------------------------- */ inline const Mesh & Mesh::getMeshFacets() const { if (!this->mesh_facets) AKANTU_SILENT_EXCEPTION( "No facet mesh is defined yet! check the buildFacets functions"); return *this->mesh_facets; } /* -------------------------------------------------------------------------- */ inline const Mesh & Mesh::getMeshParent() const { if (!this->mesh_parent) AKANTU_SILENT_EXCEPTION( "No parent mesh is defined! This is only valid in a mesh_facets"); return *this->mesh_parent; } /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_MESH_INLINE_IMPL_CC__ */ diff --git a/src/mesh/mesh_iterators.hh b/src/mesh/mesh_iterators.hh index 3d040e6a7..270f5a1fc 100644 --- a/src/mesh/mesh_iterators.hh +++ b/src/mesh/mesh_iterators.hh @@ -1,302 +1,303 @@ /** - * @file mesh_iterators.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Wed Aug 09 2017 + * @date creation: Thu Jul 16 2015 + * @date last modification: Wed Jan 31 2018 * - * @brief Set of helper classes to have fun with range based for + * @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) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_named_argument.hh" #include "aka_static_if.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_ITERATORS_HH__ #define __AKANTU_MESH_ITERATORS_HH__ namespace akantu { class MeshElementsByTypes { using elements_iterator = Array<Element>::scalar_iterator; public: explicit MeshElementsByTypes(const Array<Element> & 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<UInt> & 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<UInt> elements; }; /* ------------------------------------------------------------------------ */ class iterator { struct element_comparator { bool operator()(const Element & lhs, const Element & rhs) const { return ((rhs == ElementNull) || std::tie(lhs.ghost_type, lhs.type) < std::tie(rhs.ghost_type, rhs.type)); } }; 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<elements_iterator, elements_iterator> 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<Element> elements; }; /* -------------------------------------------------------------------------- */ namespace mesh_iterators { namespace details { template <class internal_iterator> class delegated_iterator { public: using value_type = std::remove_pointer_t< typename internal_iterator::value_type::second_type>; using difference_type = std::ptrdiff_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::forward<decltype(*(it->second))>(*(it->second)); } delegated_iterator operator++() { ++it; return *this; } bool operator==(const delegated_iterator & other) const { return other.it == it; } bool operator!=(const delegated_iterator & other) const { return other.it != it; } private: internal_iterator it; }; template <class GroupManager> class ElementGroupsIterable { public: explicit ElementGroupsIterable(GroupManager && group_manager) : group_manager(std::forward<GroupManager>(group_manager)) {} size_t size() { return group_manager.getNbElementGroups(); } decltype(auto) begin() { return delegated_iterator<decltype( group_manager.element_group_begin())>( group_manager.element_group_begin()); } decltype(auto) begin() const { return delegated_iterator<decltype( group_manager.element_group_begin())>( group_manager.element_group_begin()); } decltype(auto) end() { return delegated_iterator<decltype(group_manager.element_group_end())>( group_manager.element_group_end()); } decltype(auto) end() const { return delegated_iterator<decltype(group_manager.element_group_end())>( group_manager.element_group_end()); } private: GroupManager && group_manager; }; template <class GroupManager> class NodeGroupsIterable { public: explicit NodeGroupsIterable(GroupManager && group_manager) : group_manager(std::forward<GroupManager>(group_manager)) {} size_t size() { return group_manager.getNbNodeGroups(); } decltype(auto) begin() { return delegated_iterator<decltype(group_manager.node_group_begin())>( group_manager.node_group_begin()); } decltype(auto) begin() const { return delegated_iterator<decltype(group_manager.node_group_begin())>( group_manager.node_group_begin()); } decltype(auto) end() { return delegated_iterator<decltype(group_manager.node_group_end())>( group_manager.node_group_end()); } decltype(auto) end() const { return delegated_iterator<decltype(group_manager.node_group_end())>( group_manager.node_group_end()); } private: GroupManager && group_manager; }; } // namespace details } // namespace mesh_iterators template <class GroupManager> decltype(auto) ElementGroupsIterable(GroupManager && group_manager) { return mesh_iterators::details::ElementGroupsIterable<GroupManager>( group_manager); } template <class GroupManager> decltype(auto) NodeGroupsIterable(GroupManager && group_manager) { return mesh_iterators::details::NodeGroupsIterable<GroupManager>( group_manager); } /* -------------------------------------------------------------------------- */ template <class Func> void for_each_element(UInt nb_elements, const Array<UInt> & filter_elements, Func && function) { if (filter_elements != empty_filter) { std::for_each(filter_elements.begin(), filter_elements.end(), std::forward<Func>(function)); } else { auto && range = arange(nb_elements); std::for_each(range.begin(), range.end(), std::forward<Func>(function)); } } namespace { DECLARE_NAMED_ARGUMENT(element_filter); } /* -------------------------------------------------------------------------- */ template <class Func, typename... pack> void for_each_element(const Mesh & mesh, Func && function, pack &&... _pack) { auto requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _casper); const ElementTypeMapArray<UInt> * filter = OPTIONAL_NAMED_ARG(element_filter, nullptr); bool all_ghost_types = requested_ghost_type == _casper; auto spatial_dimension = OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()); auto element_kind = OPTIONAL_NAMED_ARG(element_kind, _ek_not_defined); for (auto ghost_type : ghost_types) { if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types)) continue; auto element_types = mesh.elementTypes(spatial_dimension, ghost_type, element_kind); if (filter) { element_types = filter->elementTypes(spatial_dimension, ghost_type, element_kind); } for (auto type : element_types) { const Array<UInt> * filter_array; if (filter) { filter_array = &((*filter)(type, ghost_type)); } else { filter_array = &empty_filter; } auto nb_elements = mesh.getNbElement(type, ghost_type); for_each_element(nb_elements, *filter_array, [&](auto && el) { auto element = Element{type, el, ghost_type}; std::forward<Func>(function)(element); }); } } } } // namespace akantu #endif /* __AKANTU_MESH_ITERATORS_HH__ */ diff --git a/src/mesh/node_group.cc b/src/mesh/node_group.cc index 45ab104a8..5ece1d1d0 100644 --- a/src/mesh/node_group.cc +++ b/src/mesh/node_group.cc @@ -1,99 +1,98 @@ /** * @file node_group.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Thu Feb 01 2018 * * @brief Implementation of the node group * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "node_group.hh" #include "dumpable.hh" #include "dumpable_inline_impl.hh" #include "mesh.hh" #if defined(AKANTU_USE_IOHELPER) #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NodeGroup::NodeGroup(const std::string & name, const Mesh & mesh, const std::string & id, const MemoryID & memory_id) : Memory(id, memory_id), name(name), node_group(alloc<UInt>(std::string(this->id + ":nodes"), 0, 1)) { #if defined(AKANTU_USE_IOHELPER) this->registerDumper<DumperParaview>("paraview_" + name, name, true); this->getDumper().registerField( "positions", new dumper::NodalField<Real, true>(mesh.getNodes(), 0, 0, &this->getNodes())); #endif } /* -------------------------------------------------------------------------- */ NodeGroup::~NodeGroup() = default; /* -------------------------------------------------------------------------- */ void NodeGroup::empty() { node_group.resize(0); } /* -------------------------------------------------------------------------- */ void NodeGroup::optimize() { std::sort(node_group.begin(), node_group.end()); Array<UInt>::iterator<> end = std::unique(node_group.begin(), node_group.end()); node_group.resize(end - node_group.begin()); } /* -------------------------------------------------------------------------- */ void NodeGroup::append(const NodeGroup & other_group) { AKANTU_DEBUG_IN(); UInt nb_nodes = node_group.size(); /// append new nodes to current list node_group.resize(nb_nodes + other_group.node_group.size()); std::copy(other_group.node_group.begin(), other_group.node_group.end(), node_group.begin() + nb_nodes); optimize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NodeGroup::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "NodeGroup [" << std::endl; stream << space << " + name: " << name << std::endl; node_group.printself(stream, indent + 1); stream << space << "]" << std::endl; } } // akantu diff --git a/src/mesh/node_group.hh b/src/mesh/node_group.hh index 8eb5f5d51..f3b36be81 100644 --- a/src/mesh/node_group.hh +++ b/src/mesh/node_group.hh @@ -1,132 +1,131 @@ /** * @file node_group.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Node group definition * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_memory.hh" #include "dumpable.hh" #include "mesh_filter.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NODE_GROUP_HH__ #define __AKANTU_NODE_GROUP_HH__ namespace akantu { class NodeGroup : public Memory, public Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NodeGroup(const std::string & name, const Mesh & mesh, const std::string & id = "node_group", const MemoryID & memory_id = 0); ~NodeGroup() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: using const_node_iterator = Array<UInt>::const_iterator<UInt>; /// empty the node group void empty(); /// iterator to the beginning of the node group inline const_node_iterator begin() const; /// iterator to the end of the node group inline const_node_iterator end() const; /// add a node and give the local position through an iterator inline const_node_iterator add(UInt node, bool check_for_duplicate = true); /// remove a node inline void remove(UInt node); #ifndef SWIG inline decltype(auto) find(UInt node) const { return node_group.find(node); } #endif /// remove duplicated nodes void optimize(); /// append a group to current one void append(const NodeGroup & other_group); /// apply a filter on current node group template <typename T> void applyNodeFilter(T & filter); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO_NOT_CONST(Nodes, node_group, Array<UInt> &); AKANTU_GET_MACRO(Nodes, node_group, const Array<UInt> &); AKANTU_GET_MACRO(Name, name, const std::string &); /// give the number of nodes in the current group inline UInt size() const; UInt * storage() { return node_group.storage(); }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// name of the group std::string name; /// list of nodes in the group Array<UInt> & node_group; /// reference to the mesh in question // const Mesh & mesh; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const NodeGroup & _this) { _this.printself(stream); return stream; } } // akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "node_group_inline_impl.cc" #endif /* __AKANTU_NODE_GROUP_HH__ */ diff --git a/src/mesh/node_group_inline_impl.cc b/src/mesh/node_group_inline_impl.cc index c165570f9..49665377d 100644 --- a/src/mesh/node_group_inline_impl.cc +++ b/src/mesh/node_group_inline_impl.cc @@ -1,99 +1,98 @@ /** * @file node_group_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Sun Aug 13 2017 * * @brief Node group inline function definitions * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ inline NodeGroup::const_node_iterator NodeGroup::begin() const { return node_group.begin(); } /* -------------------------------------------------------------------------- */ inline NodeGroup::const_node_iterator NodeGroup::end() const { return node_group.end(); } /* -------------------------------------------------------------------------- */ inline NodeGroup::const_node_iterator NodeGroup::add(UInt node, bool check_for_duplicate) { if (check_for_duplicate) { const_node_iterator it = std::find(begin(), end(), node); if (it == node_group.end()) { node_group.push_back(node); return (node_group.end() - 1); } return it; } else { node_group.push_back(node); return (node_group.end() - 1); } } /* -------------------------------------------------------------------------- */ inline void NodeGroup::remove(UInt node) { Array<UInt>::iterator<> it = this->node_group.begin(); Array<UInt>::iterator<> end = this->node_group.end(); AKANTU_DEBUG_ASSERT(it != end, "The node group is empty!!"); for (; it != node_group.end(); ++it) { if (*it == node) { it = node_group.erase(it); } } AKANTU_DEBUG_ASSERT(it != end, "The node was not found!"); } /* -------------------------------------------------------------------------- */ inline UInt NodeGroup::size() const { return node_group.size(); } /* -------------------------------------------------------------------------- */ struct FilterFunctor; template <typename T> void NodeGroup::applyNodeFilter(T & filter) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(T::type == FilterFunctor::_node_filter_functor, "NodeFilter can only apply node filter functor"); Array<UInt>::iterator<> it = this->node_group.begin(); for (; it != node_group.end(); ++it) { /// filter == true -> keep node if (!filter(*it)) { it = node_group.erase(it); } } AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc index 7be630cf2..43a36eacb 100644 --- a/src/mesh_utils/cohesive_element_inserter.cc +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -1,281 +1,282 @@ /** * @file cohesive_element_inserter.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 - * @date last modification: Sun Oct 04 2015 + * @date last modification: Mon Feb 19 2018 * * @brief Cohesive element inserter functions * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "communicator.hh" #include "element_group.hh" #include "global_ids_updater.hh" #include "mesh_iterators.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <limits> /* -------------------------------------------------------------------------- */ namespace akantu { CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, const ID & id) : Parsable(ParserType::_cohesive_inserter), id(id), mesh(mesh), mesh_facets(mesh.initMeshFacets()), insertion_facets("insertion_facets", id), insertion_limits(mesh.getSpatialDimension(), 2), check_facets("check_facets", id) { this->registerParam("cohesive_surfaces", physical_groups, _pat_parsable, "List of groups to consider for insertion"); this->registerParam("bounding_box", insertion_limits, _pat_parsable, "Global limit for insertion"); UInt spatial_dimension = mesh.getSpatialDimension(); MeshUtils::resetFacetToDouble(mesh_facets); /// init insertion limits for (UInt dim = 0; dim < spatial_dimension; ++dim) { insertion_limits(dim, 0) = std::numeric_limits<Real>::max() * Real(-1.); insertion_limits(dim, 1) = std::numeric_limits<Real>::max(); } insertion_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); } /* -------------------------------------------------------------------------- */ CohesiveElementInserter::~CohesiveElementInserter() = default; /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::parseSection(const ParserSection & section) { Parsable::parseSection(section); if (is_extrinsic) limitCheckFacets(this->check_facets); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets() { limitCheckFacets(this->check_facets); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::setLimit(SpacialDirection axis, Real first_limit, Real second_limit) { AKANTU_DEBUG_ASSERT( axis < mesh.getSpatialDimension(), "You are trying to limit insertion in a direction that doesn't exist"); insertion_limits(axis, 0) = std::min(first_limit, second_limit); insertion_limits(axis, 1) = std::max(first_limit, second_limit); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertIntrinsicElements() { limitCheckFacets(insertion_facets); return insertElements(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets( ElementTypeMapArray<bool> & check_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = true); check_facets.set(true); // remove the pure ghost elements for_each_element( mesh_facets, [&](auto && facet) { const auto & element_to_facet = mesh_facets.getElementToSubelement( facet.type, facet.ghost_type)(facet.element); auto & left = element_to_facet[0]; auto & right = element_to_facet[1]; if (right == ElementNull || (left.ghost_type == _ghost && right.ghost_type == _ghost)) { check_facets(facet) = false; return; } if (left.kind() == _ek_cohesive or right.kind() == _ek_cohesive) { check_facets(facet) = false; } }, _spatial_dimension = spatial_dimension - 1); Vector<Real> bary_facet(spatial_dimension); // set the limits to the bounding box for_each_element(mesh_facets, [&](auto && facet) { auto & need_check = check_facets(facet); if (not need_check) return; mesh_facets.getBarycenter(facet, bary_facet); UInt coord_in_limit = 0; while (coord_in_limit < spatial_dimension && bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) ++coord_in_limit; if (coord_in_limit != spatial_dimension) need_check = false; }, _spatial_dimension = spatial_dimension - 1); if (not mesh_facets.hasData("physical_names")) { AKANTU_DEBUG_ASSERT( physical_groups.size() == 0, "No physical names in the mesh but insertion limited to a group"); AKANTU_DEBUG_OUT(); return; } const auto & physical_ids = mesh_facets.getData<std::string>("physical_names"); // set the limits to the physical surfaces for_each_element(mesh_facets, [&](auto && facet) { auto & need_check = check_facets(facet); if (not need_check) return; const auto & physical_id = physical_ids(facet); auto it = find(physical_groups.begin(), physical_groups.end(), physical_id); need_check = (it != physical_groups.end()); }, _spatial_dimension = spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertElements(bool only_double_facets) { CohesiveNewNodesEvent node_event; NewElementsEvent element_event; Array<UInt> new_pairs(0, 2); UInt nb_new_elements = MeshUtils::insertCohesiveElements( mesh, mesh_facets, insertion_facets, new_pairs, element_event.getList(), only_double_facets); UInt nb_new_nodes = new_pairs.size(); node_event.getList().reserve(nb_new_nodes); node_event.getOldNodesList().reserve(nb_new_nodes); for (UInt n = 0; n < nb_new_nodes; ++n) { node_event.getList().push_back(new_pairs(n, 1)); node_event.getOldNodesList().push_back(new_pairs(n, 0)); } if (mesh.isDistributed()) { /// update nodes type updateNodesType(mesh, node_event); updateNodesType(mesh_facets, node_event); /// update global ids nb_new_nodes = this->updateGlobalIDs(node_event); /// compute total number of new elements const auto & comm = mesh.getCommunicator(); comm.allReduce(nb_new_elements, SynchronizerOperation::_sum); } if (nb_new_nodes > 0) mesh.sendEvent(node_event); if (nb_new_elements > 0) { updateInsertionFacets(); // mesh.updateTypesOffsets(_not_ghost); mesh.sendEvent(element_event); MeshUtils::resetFacetToDouble(mesh_facets); } if (mesh.isDistributed()) { /// update global ids this->synchronizeGlobalIDs(node_event); } return nb_new_elements; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::updateInsertionFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (auto && facet_gt : ghost_types) { for (auto && facet_type : mesh_facets.elementTypes(spatial_dimension - 1, facet_gt)) { auto & ins_facets = insertion_facets(facet_type, facet_gt); // this is the intrinsic case if (not is_extrinsic) continue; auto & f_check = check_facets(facet_type, facet_gt); for (auto && pair : zip(ins_facets, f_check)) { bool & ins = std::get<0>(pair); bool & check = std::get<1>(pair); if (ins) ins = check = false; } } } // resize for the newly added facets insertion_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); // resize for the newly added facets if (is_extrinsic) { check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); } else { insertion_facets.set(false); } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/mesh_utils/cohesive_element_inserter.hh b/src/mesh_utils/cohesive_element_inserter.hh index faa0481e3..688f1888e 100644 --- a/src/mesh_utils/cohesive_element_inserter.hh +++ b/src/mesh_utils/cohesive_element_inserter.hh @@ -1,192 +1,194 @@ /** * @file cohesive_element_inserter.hh * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 - * @date last modification: Fri Oct 02 2015 + * @date last modification: Sun Feb 04 2018 * * @brief Cohesive element inserter * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "mesh_utils.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #include <numeric> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ #define __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ namespace akantu { class GlobalIdsUpdater; class FacetSynchronizer; } // akantu namespace akantu { class CohesiveElementInserter : public DataAccessor<Element>, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: CohesiveElementInserter(Mesh & mesh, const ID & id = "cohesive_element_inserter"); ~CohesiveElementInserter() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// set range limitation for intrinsic cohesive element insertion void setLimit(SpacialDirection axis, Real first_limit, Real second_limit); /// insert intrinsic cohesive elements in a predefined range UInt insertIntrinsicElements(); /// insert extrinsic cohesive elements (returns the number of new /// cohesive elements) UInt insertElements(bool only_double_facets = false); /// limit check facets to match given insertion limits void limitCheckFacets(); protected: /// init parallel variables void initParallel(ElementSynchronizer & element_synchronizer); void parseSection(const ParserSection & section) override; protected: /// internal version of limitCheckFacets void limitCheckFacets(ElementTypeMapArray<bool> & check_facets); /// update facet insertion arrays after facets doubling void updateInsertionFacets(); /// update nodes type and global ids for parallel simulations /// (locally, within each processor) UInt updateGlobalIDs(NewNodesEvent & node_event); /// synchronize the global ids among the processors in parallel simulations void synchronizeGlobalIDs(NewNodesEvent & node_event); /// update nodes type void updateNodesType(Mesh & mesh, NewNodesEvent & node_event); /// functions for parallel communications inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; template <bool pack_mode> inline void packUnpackGlobalConnectivity(CommunicationBuffer & buffer, const Array<Element> & elements) const; template <bool pack_mode> inline void packUnpackGroupedInsertionData(CommunicationBuffer & buffer, const Array<Element> & elements) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO_NOT_CONST(InsertionFacetsByElement, insertion_facets, ElementTypeMapArray<bool> &); AKANTU_GET_MACRO(InsertionFacetsByElement, insertion_facets, const ElementTypeMapArray<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(InsertionFacets, insertion_facets, bool); AKANTU_GET_MACRO(CheckFacets, check_facets, const ElementTypeMapArray<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(CheckFacets, check_facets, bool); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(CheckFacets, check_facets, bool); AKANTU_GET_MACRO(MeshFacets, mesh_facets, const Mesh &); AKANTU_GET_MACRO_NOT_CONST(MeshFacets, mesh_facets, Mesh &); AKANTU_SET_MACRO(IsExtrinsic, is_extrinsic, bool); public: friend class SolidMechanicsModelCohesive; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// object id ID id; /// main mesh where to insert cohesive elements Mesh & mesh; /// mesh containing facets Mesh & mesh_facets; /// list of facets where to insert elements ElementTypeMapArray<bool> insertion_facets; /// limits for element insertion Matrix<Real> insertion_limits; /// list of groups to consider for insertion, ignored if empty std::vector<ID> physical_groups; /// vector containing facets in which extrinsic cohesive elements can be /// inserted ElementTypeMapArray<bool> check_facets; /// global connectivity ids updater std::unique_ptr<GlobalIdsUpdater> global_ids_updater; /// is this inserter used in extrinsic bool is_extrinsic{false}; }; class CohesiveNewNodesEvent : public NewNodesEvent { public: CohesiveNewNodesEvent() = default; ~CohesiveNewNodesEvent() override = default; AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array<UInt> &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array<UInt> &); private: Array<UInt> old_nodes; }; } // akantu #include "cohesive_element_inserter_inline_impl.cc" #endif /* __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ */ diff --git a/src/mesh_utils/cohesive_element_inserter_inline_impl.cc b/src/mesh_utils/cohesive_element_inserter_inline_impl.cc index 65255ff86..d53f12d16 100644 --- a/src/mesh_utils/cohesive_element_inserter_inline_impl.cc +++ b/src/mesh_utils/cohesive_element_inserter_inline_impl.cc @@ -1,105 +1,121 @@ /** * @file cohesive_element_inserter_inline_impl.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * + * @date creation: Wed Nov 05 2014 + * @date last modification: Fri Dec 08 2017 * * @brief Cohesive element inserter inline functions * * @section LICENSE * - * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 <http://www.gnu.org/licenses/>. + * */ + /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COHESIVE_ELEMENT_INSERTER_INLINE_IMPL_CC__ #define __AKANTU_COHESIVE_ELEMENT_INSERTER_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt CohesiveElementInserter::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if (tag == _gst_ce_groups) { size = elements.size() * (sizeof(bool) + sizeof(unsigned int)); } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void CohesiveElementInserter::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); if (tag == _gst_ce_groups) packUnpackGroupedInsertionData<true>(buffer, elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void CohesiveElementInserter::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (tag == _gst_ce_groups) packUnpackGroupedInsertionData<false>(buffer, elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool pack_mode> inline void CohesiveElementInserter::packUnpackGroupedInsertionData( CommunicationBuffer & buffer, const Array<Element> & elements) const { AKANTU_DEBUG_IN(); auto current_element_type = _not_defined; auto current_ghost_type = _casper; auto & physical_names = mesh_facets.registerData<UInt>("physical_names"); Array<bool> * vect = nullptr; Array<UInt> * vect2 = nullptr; for (const auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; vect = &const_cast<Array<bool> &>(insertion_facets(el.type, el.ghost_type)); vect2 = &(physical_names(el.type, el.ghost_type)); } Vector<bool> data(vect->storage() + el.element, 1); Vector<unsigned int> data2(vect2->storage() + el.element, 1); if (pack_mode) { buffer << data; buffer << data2; } else { buffer >> data; buffer >> data2; } } AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_COHESIVE_ELEMENT_INSERTER_INLINE_IMPL_CC__ */ diff --git a/src/mesh_utils/cohesive_element_inserter_parallel.cc b/src/mesh_utils/cohesive_element_inserter_parallel.cc index a8e5cac48..a61281338 100644 --- a/src/mesh_utils/cohesive_element_inserter_parallel.cc +++ b/src/mesh_utils/cohesive_element_inserter_parallel.cc @@ -1,77 +1,93 @@ /** * @file cohesive_element_inserter_parallel.cc * + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * + * @date creation: Wed Nov 05 2014 + * @date last modification: Fri Dec 08 2017 * * @brief Parallel functions for the cohesive element inserter * * @section LICENSE * - * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 <http://www.gnu.org/licenses/>. + * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "global_ids_updater.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::initParallel(ElementSynchronizer & synchronizer) { global_ids_updater = std::make_unique<GlobalIdsUpdater>(mesh, synchronizer); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::updateNodesType(Mesh & mesh, NewNodesEvent & node_event) { AKANTU_DEBUG_IN(); auto & cohesive_node_event = dynamic_cast<CohesiveNewNodesEvent &>(node_event); auto & new_nodes = cohesive_node_event.getList(); auto & old_nodes = cohesive_node_event.getOldNodesList(); UInt local_nb_new_nodes = new_nodes.size(); MeshAccessor mesh_accessor(mesh); auto & nodes_type = mesh_accessor.getNodesType(); UInt nb_old_nodes = nodes_type.size(); nodes_type.resize(nb_old_nodes + local_nb_new_nodes); for (auto && data : zip(old_nodes, new_nodes)) { UInt old_node, new_node; std::tie(old_node, new_node) = data; nodes_type(new_node) = nodes_type(old_node); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::updateGlobalIDs(NewNodesEvent & node_event) { AKANTU_DEBUG_IN(); Array<UInt> & doubled_nodes = node_event.getList(); UInt total_nb_new_nodes = global_ids_updater->updateGlobalIDsLocally(doubled_nodes.size()); AKANTU_DEBUG_OUT(); return total_nb_new_nodes; } void CohesiveElementInserter::synchronizeGlobalIDs( NewNodesEvent & /*node_event*/) { AKANTU_DEBUG_IN(); global_ids_updater->synchronizeGlobalIDs(); AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/mesh_utils/global_ids_updater.cc b/src/mesh_utils/global_ids_updater.cc index bd3ae404d..5f0198e60 100644 --- a/src/mesh_utils/global_ids_updater.cc +++ b/src/mesh_utils/global_ids_updater.cc @@ -1,57 +1,56 @@ /** * @file global_ids_updater.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Apr 13 2012 - * @date last modification: Fri Oct 02 2015 + * @date last modification: Fri Dec 08 2017 * * @brief Functions of the GlobalIdsUpdater * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "global_ids_updater.hh" #include "element_synchronizer.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ namespace akantu { UInt GlobalIdsUpdater::updateGlobalIDs(UInt old_nb_nodes) { UInt total_nb_new_nodes = this->updateGlobalIDsLocally(old_nb_nodes); this->synchronizeGlobalIDs(); return total_nb_new_nodes; } UInt GlobalIdsUpdater::updateGlobalIDsLocally(UInt old_nb_nodes) { UInt total_nb_new_nodes = MeshUtils::updateLocalMasterGlobalConnectivity(mesh, old_nb_nodes); return total_nb_new_nodes; } void GlobalIdsUpdater::synchronizeGlobalIDs() { this->synchronizer.synchronizeOnce(*this, _gst_giu_global_conn); } } // akantu diff --git a/src/mesh_utils/global_ids_updater.hh b/src/mesh_utils/global_ids_updater.hh index bc2b6199a..5869c99b4 100644 --- a/src/mesh_utils/global_ids_updater.hh +++ b/src/mesh_utils/global_ids_updater.hh @@ -1,100 +1,102 @@ /** * @file global_ids_updater.hh * + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Oct 02 2015 + * @date last modification: Fri Dec 08 2017 * * @brief Class that updates the global ids of new nodes that are * inserted in the mesh. The functions in this class must be called * after updating the node types * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GLOBAL_IDS_UPDATER_HH__ #define __AKANTU_GLOBAL_IDS_UPDATER_HH__ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class ElementSynchronizer; } // akantu namespace akantu { class GlobalIdsUpdater : public DataAccessor<Element> { public: GlobalIdsUpdater(Mesh & mesh, ElementSynchronizer & synchronizer) : mesh(mesh), synchronizer(synchronizer) {} /// function to update and synchronize the global connectivity of /// new inserted nodes. It must be called after updating the node /// types. (It calls in sequence the functions /// updateGlobalIDsLocally and synchronizeGlobalIDs) UInt updateGlobalIDs(UInt old_nb_nodes); /// function to update the global connectivity (only locally) of new /// inserted nodes. It must be called after updating the node types. UInt updateGlobalIDsLocally(UInt old_nb_nodes); /// function to synchronize the global connectivity of new inserted /// nodes among the processors. It must be called after updating the /// node types. void synchronizeGlobalIDs(); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; /* ------------------------------------------------------------------------ */ template <bool pack_mode> inline void packUnpackGlobalConnectivity(CommunicationBuffer & buffer, const Array<Element> & elements) const; /* ------------------------------------------------------------------------ */ /* Members */ /* ------------------------------------------------------------------------ */ private: /// Reference to the mesh to update Mesh & mesh; /// distributed synchronizer to communicate the connectivity ElementSynchronizer & synchronizer; }; } // akantu #include "global_ids_updater_inline_impl.cc" #endif /* __AKANTU_GLOBAL_IDS_UPDATER_HH__ */ diff --git a/src/mesh_utils/global_ids_updater_inline_impl.cc b/src/mesh_utils/global_ids_updater_inline_impl.cc index 77a4ffe24..4fc0e7b2b 100644 --- a/src/mesh_utils/global_ids_updater_inline_impl.cc +++ b/src/mesh_utils/global_ids_updater_inline_impl.cc @@ -1,132 +1,132 @@ /** * @file global_ids_updater_inline_impl.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Oct 02 2015 - * @date last modification: Sun Oct 04 2015 + * @date last modification: Sun Aug 13 2017 * * @brief Implementation of the inline functions of GlobalIdsUpdater * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "global_ids_updater.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GLOBAL_IDS_UPDATER_INLINE_IMPL_CC__ #define __AKANTU_GLOBAL_IDS_UPDATER_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt GlobalIdsUpdater::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { UInt size = 0; if (elements.size() == 0) return size; if (tag == _gst_giu_global_conn) size += Mesh::getNbNodesPerElementList(elements) * sizeof(UInt); return size; } /* -------------------------------------------------------------------------- */ inline void GlobalIdsUpdater::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_giu_global_conn) packUnpackGlobalConnectivity<true>(buffer, elements); } /* -------------------------------------------------------------------------- */ inline void GlobalIdsUpdater::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_giu_global_conn) packUnpackGlobalConnectivity<false>(buffer, elements); } /* -------------------------------------------------------------------------- */ template <bool pack_mode> inline void GlobalIdsUpdater::packUnpackGlobalConnectivity( CommunicationBuffer & buffer, const Array<Element> & elements) const { AKANTU_DEBUG_IN(); ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; Array<UInt>::const_vector_iterator conn_begin; UInt nb_nodes_per_elem = 0; UInt index; Array<UInt> & global_nodes_ids = mesh.getGlobalNodesIds(); Array<Element>::const_scalar_iterator it = elements.begin(); Array<Element>::const_scalar_iterator end = elements.end(); for (; it != end; ++it) { const Element & el = *it; if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; const Array<UInt> & connectivity = mesh.getConnectivity(current_element_type, current_ghost_type); nb_nodes_per_elem = connectivity.getNbComponent(); conn_begin = connectivity.begin(nb_nodes_per_elem); } /// get element connectivity const Vector<UInt> current_conn = conn_begin[el.element]; /// loop on all connectivity nodes for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = current_conn(n); if (pack_mode) { /// if node is local or master pack its global id, otherwise /// dummy data if (mesh.isLocalOrMasterNode(node)) index = global_nodes_ids(node); else index = UInt(-1); buffer << index; } else { buffer >> index; /// update slave nodes' index if (index != UInt(-1) && mesh.isSlaveNode(node)) global_nodes_ids(node) = index; } } } AKANTU_DEBUG_OUT(); } } // akantu #endif /* __AKANTU_GLOBAL_IDS_UPDATER_INLINE_IMPL_CC__ */ diff --git a/src/mesh_utils/mesh_partition.cc b/src/mesh_utils/mesh_partition.cc index d7a27e34f..7bb771e62 100644 --- a/src/mesh_utils/mesh_partition.cc +++ b/src/mesh_utils/mesh_partition.cc @@ -1,434 +1,433 @@ /** * @file mesh_partition.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Aug 17 2010 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Wed Jan 24 2018 * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_partition.hh" #include "aka_iterators.hh" #include "aka_types.hh" #include "mesh_accessor.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <numeric> #include <unordered_map> /* -------------------------------------------------------------------------- */ 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(); UInt nb_total_element = 0; for (auto && type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { linearized_offsets.push_back(std::make_pair(type, nb_total_element)); nb_total_element += mesh.getConnectivity(type).size(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MeshPartition::~MeshPartition() = default; /* -------------------------------------------------------------------------- */ UInt MeshPartition::linearized(const Element & element) { auto it = std::find_if(linearized_offsets.begin(), linearized_offsets.end(), [&element](auto & a) { return a.first == element.type; }); AKANTU_DEBUG_ASSERT(it != linearized_offsets.end(), "A bug might be crawling around this corner..."); return (it->second + element.element); } /* -------------------------------------------------------------------------- */ Element MeshPartition::unlinearized(UInt lin_element) { ElementType type{_not_defined}; UInt offset{0}; for (auto & pair : linearized_offsets) { if (lin_element < pair.second) continue; std::tie(type, offset) = pair; } return Element{type, lin_element - offset, _not_ghost}; } /* -------------------------------------------------------------------------- */ /** * 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<Int> & dxadj, Array<Int> & dadjncy, Array<Int> & edge_loads, const EdgeLoadFunctor & edge_load_func) { AKANTU_DEBUG_IN(); std::map<ElementType, std::tuple<const Array<UInt> *, UInt, UInt>> connectivities; UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_total_element{0}; for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { auto type_p1 = mesh.getP1ElementType(type); auto nb_nodes_per_element_p1 = mesh.getNbNodesPerElement(type_p1); auto magic_number = mesh.getNbNodesPerElement(mesh.getFacetType(type_p1)); const auto & conn = mesh.getConnectivity(type, _not_ghost); connectivities[type] = std::make_tuple(&conn, nb_nodes_per_element_p1, magic_number); nb_total_element += conn.size(); } CSR<Element> node_to_elem; MeshUtils::buildNode2Elements(mesh, node_to_elem); dxadj.resize(nb_total_element + 1); /// initialize the dxadj array auto dxadj_it = dxadj.begin(); for (auto & pair : connectivities) { const auto & connectivity = *std::get<0>(pair.second); auto nb_nodes_per_element_p1 = std::get<1>(pair.second); std::fill_n(dxadj_it, connectivity.size(), nb_nodes_per_element_p1); dxadj_it += connectivity.size(); } /// 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<UInt, UInt> weight_map; for (auto & pair : connectivities) { auto type = pair.first; const auto & connectivity = *std::get<0>(pair.second); auto nb_nodes_per_element = std::get<1>(pair.second); auto magic_number = std::get<2>(pair.second); Element element{type, 0, _not_ghost}; for (const auto & conn : make_view(connectivity, connectivity.getNbComponent())) { auto linearized_el = linearized(element); /// fill the weight map for (UInt n : arange(nb_nodes_per_element)) { auto && node = conn(n); for (auto k = node_to_elem.rbegin(node); k != node_to_elem.rend(node); --k) { auto & current_element = *k; auto current_el = linearized(current_element); AKANTU_DEBUG_ASSERT(current_el != UInt(-1), "Linearized element not found"); if (current_el <= linearized_el) break; auto weight_map_insert = weight_map.insert(std::make_pair(current_el, 1)); if (not weight_map_insert.second) (weight_map_insert.first->second)++; } } /// each element with a weight of the size of a facet are adjacent for (auto & weight_pair : weight_map) { auto & adjacent_el = weight_pair.first; auto magic = weight_pair.second; if (magic != magic_number) continue; #if defined(AKANTU_COHESIVE_ELEMENT) /// Patch in order to prevent neighboring cohesive elements /// from detecting each other auto adjacent_element = unlinearized(adjacent_el); auto el_kind = element.kind(); auto adjacent_el_kind = adjacent_element.kind(); if (el_kind == adjacent_el_kind && el_kind == _ek_cohesive) continue; #endif UInt index_adj = dxadj(adjacent_el)++; UInt index_lin = dxadj(linearized_el)++; dadjncy(index_lin) = adjacent_el; dadjncy(index_adj) = linearized_el; } element.element++; weight_map.clear(); } } Int k_start = 0, linerized_el = 0, j = 0; for (auto & pair : connectivities) { const auto & connectivity = *std::get<0>(pair.second); auto nb_nodes_per_element_p1 = std::get<1>(pair.second); auto nb_element = connectivity.size(); for (UInt el = 0; el < nb_element; ++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; } } 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 = unlinearized(i); Element el_adj = unlinearized(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<Element> 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)) { 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<UInt> & 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<UInt> list_adj_part; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity.storage()[el * nb_nodes_per_element + n]; CSR<Element>::iterator ne; for (ne = node_to_elem.begin(node); ne != node_to_elem.end(node); ++ne) { const Element & adj_element = *ne; UInt adj_el = linearized(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<UInt> & 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<std::vector<Element>> & elem_to_subelem = mesh.getElementToSubelement(type, _not_ghost); for (UInt i(0); i < mesh.getNbElement(type, _not_ghost); ++i) { // Facet loop const std::vector<Element> & adjacent_elems = elem_to_subelem(i); if (!adjacent_elems.empty()) { Element min_elem{_max_element_type, std::numeric_limits<UInt>::max(), *ghost_type_t::end()}; UInt min_part(std::numeric_limits<UInt>::max()); std::set<UInt> 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); 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<UInt> & pairs) { AKANTU_DEBUG_IN(); if (pairs.size() == 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<UInt> & conn = const_cast<Array<UInt> &>(mesh.getConnectivity(type, _not_ghost)); UInt nb_nodes_per_element = conn.getNbComponent(); UInt nb_element = conn.size(); Array<UInt> & saved_conn = saved_connectivity.alloc( nb_element, nb_nodes_per_element, type, _not_ghost); saved_conn.copy(conn); for (UInt i = 0; i < pairs.size(); ++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(); MeshAccessor mesh_accessor(const_cast<Mesh &>(mesh)); for (auto && type : saved_connectivity.elementTypes( spatial_dimension, _not_ghost, _ek_not_defined)) { auto & conn = mesh_accessor.getConnectivity(type, _not_ghost); auto & saved_conn = saved_connectivity(type, _not_ghost); conn.copy(saved_conn); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool MeshPartition::hasPartitions(const ElementType & type, const GhostType & ghost_type) { return partitions.exists(type, ghost_type); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/mesh_utils/mesh_partition.hh b/src/mesh_utils/mesh_partition.hh index 175c8c1ef..bd1b703f9 100644 --- a/src/mesh_utils/mesh_partition.hh +++ b/src/mesh_utils/mesh_partition.hh @@ -1,155 +1,154 @@ /** * @file mesh_partition.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Sep 01 2015 + * @date last modification: Tue Jan 23 2018 * * @brief tools to partitionate a mesh * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_PARTITION_HH__ #define __AKANTU_MESH_PARTITION_HH__ /* -------------------------------------------------------------------------- */ #include "aka_csr.hh" #include "aka_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class MeshPartition : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshPartition(const Mesh & mesh, UInt spatial_dimension, const ID & id = "MeshPartitioner", const MemoryID & memory_id = 0); ~MeshPartition() override; class EdgeLoadFunctor { public: virtual Int operator()(const Element & el1, const Element & el2) const noexcept = 0; }; class ConstEdgeLoadFunctor : public EdgeLoadFunctor { public: inline Int operator()(const Element &, const Element &) const noexcept override { return 1; } }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// define a partition of the mesh virtual void partitionate(UInt nb_part, const EdgeLoadFunctor & edge_load_func = ConstEdgeLoadFunctor(), const Array<UInt> & pairs = Array<UInt>()) = 0; /// reorder the nodes to reduce the filling during the factorization of a /// matrix that has a profil based on the connectivity of the mesh virtual void reorder() = 0; /// fill the partitions array with a given linearized partition information void fillPartitionInformation(const Mesh & mesh, const Int * linearized_partitions); protected: /// build the dual graph of the mesh, for all element of spatial_dimension void buildDualGraph(Array<Int> & dxadj, Array<Int> & dadjncy, Array<Int> & edge_loads, const EdgeLoadFunctor & edge_load_func); /// tweak the mesh to handle the PBC pairs void tweakConnectivity(const Array<UInt> & pairs); /// restore the mesh that has been tweaked void restoreConnectivity(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: bool hasPartitions(const ElementType & type, const GhostType & ghost_type); AKANTU_GET_MACRO(Partitions, partitions, const ElementTypeMapArray<UInt> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Partition, partitions, UInt); AKANTU_GET_MACRO(GhostPartitionCSR, ghost_partitions_csr, const ElementTypeMap<CSR<UInt>> &); AKANTU_GET_MACRO(NbPartition, nb_partitions, UInt); AKANTU_SET_MACRO(NbPartition, nb_partitions, UInt); protected: UInt linearized(const Element & element); Element unlinearized(UInt lin_element); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id std::string id; /// the mesh to partition const Mesh & mesh; /// dimension of the elements to consider in the mesh UInt spatial_dimension; /// number of partitions UInt nb_partitions; /// partition numbers ElementTypeMapArray<UInt> partitions; ElementTypeMap<CSR<UInt>> ghost_partitions_csr; ElementTypeMapArray<UInt> ghost_partitions; ElementTypeMapArray<UInt> ghost_partitions_offset; Array<UInt> * permutation; ElementTypeMapArray<UInt> saved_connectivity; // vector of pair to ensure the iteration order std::vector<std::pair<ElementType, UInt>> linearized_offsets; }; } // namespace akantu #ifdef AKANTU_USE_SCOTCH #include "mesh_partition_scotch.hh" #endif #endif /* __AKANTU_MESH_PARTITION_HH__ */ diff --git a/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.cc b/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.cc index 78d5990bb..aad595cc1 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.cc +++ b/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.cc @@ -1,141 +1,141 @@ /** * @file mesh_partition_mesh_data.cc * * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Fri May 03 2013 - * @date last modification: Wed Nov 11 2015 + * @date last modification: Tue Feb 20 2018 * * @brief implementation of the MeshPartitionMeshData class * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "mesh_partition_mesh_data.hh" #if !defined(AKANTU_NDEBUG) #include <set> #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MeshPartitionMeshData::MeshPartitionMeshData(const Mesh & mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : MeshPartition(mesh, spatial_dimension, id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MeshPartitionMeshData::MeshPartitionMeshData( const Mesh & mesh, const ElementTypeMapArray<UInt> & mapping, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : MeshPartition(mesh, spatial_dimension, id, memory_id), partition_mapping(&mapping) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartitionMeshData::partitionate(UInt nb_part, __attribute__((unused)) const EdgeLoadFunctor & edge_load_func, const Array<UInt> & pairs) { AKANTU_DEBUG_IN(); tweakConnectivity(pairs); nb_partitions = nb_part; GhostType ghost_type = _not_ghost; UInt spatial_dimension = mesh.getSpatialDimension(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type, _ek_not_defined); UInt linearized_el = 0; UInt nb_elements = mesh.getNbElement(mesh.getSpatialDimension(), ghost_type); auto * partition_list = new Int[nb_elements]; #if !defined(AKANTU_NDEBUG) std::set<UInt> partitions; #endif for (; it != end; ++it) { ElementType type = *it; const Array<UInt> & partition_array = (*partition_mapping)(type, ghost_type); Array<UInt>::const_iterator<Vector<UInt>> p_it = partition_array.begin(1); Array<UInt>::const_iterator<Vector<UInt>> p_end = partition_array.end(1); AKANTU_DEBUG_ASSERT(UInt(p_end - p_it) == mesh.getNbElement(type, ghost_type), "The partition mapping does not have the right number " << "of entries for type " << type << " and ghost type " << ghost_type << "." << " Tags=" << p_end - p_it << " Mesh=" << mesh.getNbElement(type, ghost_type)); for (; p_it != p_end; ++p_it, ++linearized_el) { partition_list[linearized_el] = (*p_it)(0); #if !defined(AKANTU_NDEBUG) partitions.insert((*p_it)(0)); #endif } } #if !defined(AKANTU_NDEBUG) AKANTU_DEBUG_ASSERT(partitions.size() == nb_part, "The number of real partitions does not match with the " "number of asked partitions"); #endif fillPartitionInformation(mesh, partition_list); delete[] partition_list; restoreConnectivity(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartitionMeshData::reorder() { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ void MeshPartitionMeshData::setPartitionMapping( const ElementTypeMapArray<UInt> & mapping) { partition_mapping = &mapping; } /* -------------------------------------------------------------------------- */ void MeshPartitionMeshData::setPartitionMappingFromMeshData( const std::string & data_name) { partition_mapping = &(mesh.getData<UInt>(data_name)); } } // akantu diff --git a/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.hh b/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.hh index d2405af38..efc3a394c 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.hh +++ b/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.hh @@ -1,94 +1,93 @@ /** * @file mesh_partition_mesh_data.hh * * @author Dana Christen <dana.christen@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief mesh partitioning based on data provided in the mesh * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_PARTITION_MESH_DATA_HH__ #define __AKANTU_MESH_PARTITION_MESH_DATA_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh_partition.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class MeshPartitionMeshData : public MeshPartition { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshPartitionMeshData(const Mesh & mesh, UInt spatial_dimension, const ID & id = "MeshPartitionerMeshData", const MemoryID & memory_id = 0); MeshPartitionMeshData(const Mesh & mesh, const ElementTypeMapArray<UInt> & mapping, UInt spatial_dimension, const ID & id = "MeshPartitionerMeshData", const MemoryID & memory_id = 0); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void partitionate(UInt nb_part, const EdgeLoadFunctor & edge_load_func = ConstEdgeLoadFunctor(), const Array<UInt> & pairs = Array<UInt>()) override; void reorder() override; void setPartitionMapping(const ElementTypeMapArray<UInt> & mapping); void setPartitionMappingFromMeshData(const std::string & data_name); private: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: const ElementTypeMapArray<UInt> * partition_mapping; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_MESH_PARTITION_MESH_DATA_HH__ */ diff --git a/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc b/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc index 9d0cd28f1..f12652bff 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc +++ b/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc @@ -1,479 +1,479 @@ /** * @file mesh_partition_scotch.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Tue Feb 20 2018 * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "mesh_partition_scotch.hh" #include "aka_common.hh" #include "aka_random_generator.hh" #include "aka_static_if.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <cstdio> #include <fstream> /* -------------------------------------------------------------------------- */ #if !defined(AKANTU_USE_PTSCOTCH) #ifndef AKANTU_SCOTCH_NO_EXTERN extern "C" { #endif // AKANTU_SCOTCH_NO_EXTERN #include <scotch.h> #ifndef AKANTU_SCOTCH_NO_EXTERN } #endif // AKANTU_SCOTCH_NO_EXTERN #else // AKANTU_USE_PTSCOTCH #include <ptscotch.h> #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 static_assert( sizeof(Int) == sizeof(SCOTCH_Num), "The integer type of Akantu does not match the one from Scotch"); static_if(aka::bool_constant_v<scotch_version >= 6>) .then([](auto && y) { SCOTCH_randomSeed(y); }) .else_([](auto && y) { srandom(y); })( std::forward<UInt>(RandomGenerator<UInt>::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; auto * verttab = new SCOTCH_Num[vnodnbr + velmnbr + 1]; SCOTCH_Num * vendtab = verttab + 1; SCOTCH_Num * velotab = nullptr; SCOTCH_Num * vnlotab = nullptr; SCOTCH_Num * vlbltab = nullptr; 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<UInt> & 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; auto * 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<UInt> & 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<UInt> & 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; } } } auto * 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; const Array<Real> & 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<UInt> & pairs) { AKANTU_DEBUG_IN(); nb_partitions = nb_part; tweakConnectivity(pairs); AKANTU_DEBUG_INFO("Partitioning the mesh " << mesh.getID() << " in " << nb_part << " parts."); Array<Int> dxadj; Array<Int> dadjncy; Array<Int> 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.size() - 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 = nullptr; // array of after-last indices in edgetab SCOTCH_Num * velotab = nullptr; // 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 = nullptr; // 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; const Array<Real> & 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); auto 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<UInt> & connectivity = mesh.getConnectivity(type); Vector<Real> 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<Real>(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; auto * permtab = new SCOTCH_Num[nb_nodes]; SCOTCH_Num * peritab = nullptr; SCOTCH_Num cblknbr = 0; SCOTCH_Num * rangtab = nullptr; SCOTCH_Num * treetab = nullptr; /// 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) { auto 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<UInt> & 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 auto * 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(); } } // namespace akantu diff --git a/src/mesh_utils/mesh_partition/mesh_partition_scotch.hh b/src/mesh_utils/mesh_partition/mesh_partition_scotch.hh index 2dc3e385b..abe747b96 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_scotch.hh +++ b/src/mesh_utils/mesh_partition/mesh_partition_scotch.hh @@ -1,78 +1,77 @@ /** * @file mesh_partition_scotch.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief mesh partitioning based on libScotch * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_PARTITION_SCOTCH_HH__ #define __AKANTU_MESH_PARTITION_SCOTCH_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh_partition.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class MeshPartitionScotch : public MeshPartition { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshPartitionScotch(const Mesh & mesh, UInt spatial_dimension, const ID & id = "mesh_partition_scotch", const MemoryID & memory_id = 0); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void partitionate(UInt nb_part, const EdgeLoadFunctor & edge_load_func = ConstEdgeLoadFunctor(), const Array<UInt> & pairs = Array<UInt>()) override; void reorder() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; } // akantu #endif /* __AKANTU_MESH_PARTITION_SCOTCH_HH__ */ diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 7883e4a37..cc68fe58f 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2091 +1,2090 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Aug 20 2010 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Wed Feb 21 2018 * * @brief All mesh utils necessary for various tasks * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "fe_engine.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #include <limits> #include <numeric> #include <queue> #include <set> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<Element> & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); /// count number of occurrence of each node UInt nb_nodes = mesh.getNbNodes(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); // AKANTU_DEBUG_ASSERT( // mesh.firstType(spatial_dimension) != mesh.lastType(spatial_dimension), // "Some elements must be found in right dimension to compute facets!"); for (auto && ghost_type : ghost_types) { for (auto && type : mesh.elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { UInt nb_element = mesh.getNbElement(type, ghost_type); auto conn_it = mesh.getConnectivity(type, ghost_type) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) for (UInt n = 0; n < conn_it->size(); ++n) ++node_to_elem.rowOffset((*conn_it)(n)); } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); /// rearrange element to get the node-element list Element e; node_to_elem.beginInsertions(); for (auto && ghost_type : ghost_types) { e.ghost_type = ghost_type; for (auto && type : mesh.elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { e.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); auto conn_it = mesh.getConnectivity(type, ghost_type) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; for (UInt n = 0; n < conn_it->size(); ++n) node_to_elem.insertInRow((*conn_it)(n), e); } } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR<UInt> & node_to_elem, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, ghost_type).size(); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) ++node_to_elem.rowOffset(conn_val[el_offset + n]); } /// convert the occurrence array in a csr one node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { node_to_elem.insertInRow(conn_val[el_offset + n], el); } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { mesh.getConnectivity(*it, *gt).resize(0); // \todo inform the mesh event handler } } buildFacetsDimension(mesh, mesh, true, spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT( mesh_facets.isMeshFacets(), "The mesh_facets should be initialized with initMeshFacets"); /// generate facets buildFacetsDimension(mesh, mesh_facets, false, from_dimension); /// copy nodes type MeshAccessor mesh_accessor_facets(mesh_facets); mesh_accessor_facets.getNodesType().copy(mesh.getNodesType()); /// sort facets and generate sub-facets for (UInt i = from_dimension - 1; i > to_dimension; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension) { AKANTU_DEBUG_IN(); // save the current parent of mesh_facets and set it temporarly to mesh since // mesh is the one containing the elements for which mesh_facets has the // sub-elements // example: if the function is called with mesh = mesh_facets const Mesh * mesh_facets_parent = nullptr; try { mesh_facets_parent = &mesh_facets.getMeshParent(); } catch (...) { } mesh_facets.defineMeshParent(mesh); MeshAccessor mesh_accessor(mesh_facets); UInt spatial_dimension = mesh.getSpatialDimension(); const Array<Real> & mesh_facets_nodes = mesh_facets.getNodes(); const auto mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); CSR<Element> node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array<UInt> counter; std::vector<Element> connected_elements; // init the SubelementToElement data to improve performance for (auto && ghost_type : ghost_types) { for (auto && type : mesh.elementTypes(dimension, ghost_type)) { mesh_accessor.getSubelementToElement(type, ghost_type); auto facet_types = mesh.getAllFacetTypes(type); for (auto && ft : arange(facet_types.size())) { auto facet_type = facet_types(ft); mesh_accessor.getElementToSubelement(facet_type, ghost_type); mesh_accessor.getConnectivity(facet_type, ghost_type); } } } const ElementSynchronizer * synchronizer = nullptr; if (mesh.isDistributed()) { synchronizer = &(mesh.getElementSynchronizer()); } Element current_element; for (auto && ghost_type : ghost_types) { GhostType facet_ghost_type = ghost_type; current_element.ghost_type = ghost_type; for (auto && type : mesh.elementTypes(dimension, ghost_type)) { auto facet_types = mesh.getAllFacetTypes(type); current_element.type = type; for (auto && ft : arange(facet_types.size())) { auto facet_type = facet_types(ft); auto nb_element = mesh.getNbElement(type, ghost_type); auto element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, ghost_type); auto connectivity_facets = &mesh_facets.getConnectivity(facet_type, ghost_type); auto nb_facet_per_element = mesh.getNbFacetsPerElement(type, ft); const auto & element_connectivity = mesh.getConnectivity(type, ghost_type); Matrix<const UInt> facet_local_connectivity( mesh.getFacetLocalConnectivity(type, ft)); auto nb_nodes_per_facet = connectivity_facets->getNbComponent(); Vector<UInt> facet(nb_nodes_per_facet); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; for (UInt f = 0; f < nb_facet_per_element; ++f) { for (UInt n = 0; n < nb_nodes_per_facet; ++n) facet(n) = element_connectivity(el, facet_local_connectivity(f, n)); UInt first_node_nb_elements = node_to_elem.getNbCols(facet(0)); counter.resize(first_node_nb_elements); counter.clear(); // loop over the other nodes to search intersecting elements, // which are the elements that share another node with the // starting element after first_node UInt local_el = 0; auto first_node_elements = node_to_elem.begin(facet(0)); auto first_node_elements_end = node_to_elem.end(facet(0)); for (; first_node_elements != first_node_elements_end; ++first_node_elements, ++local_el) { for (UInt n = 1; n < nb_nodes_per_facet; ++n) { auto node_elements_begin = node_to_elem.begin(facet(n)); auto node_elements_end = node_to_elem.end(facet(n)); counter(local_el) += std::count(node_elements_begin, node_elements_end, *first_node_elements); } } // counting the number of elements connected to the facets and // taking the minimum element number, because the facet should // be inserted just once UInt nb_element_connected_to_facet = 0; Element minimum_el = ElementNull; connected_elements.clear(); for (UInt el_f = 0; el_f < first_node_nb_elements; el_f++) { Element real_el = node_to_elem(facet(0), el_f); if (not(counter(el_f) == nb_nodes_per_facet - 1)) continue; ++nb_element_connected_to_facet; minimum_el = std::min(minimum_el, real_el); connected_elements.push_back(real_el); } if (minimum_el != current_element) continue; bool full_ghost_facet = false; UInt n = 0; while (n < nb_nodes_per_facet && mesh.isPureGhostNode(facet(n))) ++n; if (n == nb_nodes_per_facet) full_ghost_facet = true; if (full_ghost_facet) continue; if (boundary_only and nb_element_connected_to_facet != 1) continue; std::vector<Element> elements; // build elements_on_facets: linearized_el must come first // in order to store the facet in the correct direction // and avoid to invert the sign in the normal computation elements.push_back(current_element); if (nb_element_connected_to_facet == 1) { /// boundary facet elements.push_back(ElementNull); } else if (nb_element_connected_to_facet == 2) { /// internal facet elements.push_back(connected_elements[1]); /// check if facet is in between ghost and normal /// elements: if it's the case, the facet is either /// ghost or not ghost. The criterion to decide this /// is arbitrary. It was chosen to check the processor /// id (prank) of the two neighboring elements. If /// prank of the ghost element is lower than prank of /// the normal one, the facet is not ghost, otherwise /// it's ghost GhostType gt[2] = {_not_ghost, _not_ghost}; for (UInt el = 0; el < connected_elements.size(); ++el) gt[el] = connected_elements[el].ghost_type; if (gt[0] != gt[1] and (gt[0] == _not_ghost or gt[1] == _not_ghost)) { UInt prank[2]; for (UInt el = 0; el < 2; ++el) { prank[el] = synchronizer->getRank(connected_elements[el]); } // ugly trick from Marco detected :P bool ghost_one = (gt[0] != _ghost); if (prank[ghost_one] > prank[!ghost_one]) facet_ghost_type = _not_ghost; else facet_ghost_type = _ghost; connectivity_facets = &mesh_facets.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_facets.getElementToSubelement( facet_type, facet_ghost_type); } } else { /// facet of facet for (UInt i = 1; i < nb_element_connected_to_facet; ++i) { elements.push_back(connected_elements[i]); } } element_to_subelement->push_back(elements); connectivity_facets->push_back(facet); /// current facet index UInt current_facet = connectivity_facets->size() - 1; /// loop on every element connected to current facet and /// insert current facet in the first free spot of the /// subelement_to_element vector for (UInt elem = 0; elem < elements.size(); ++elem) { Element loc_el = elements[elem]; if (loc_el.type == _not_defined) continue; Array<Element> & subelement_to_element = mesh_facets.getSubelementToElement(loc_el.type, loc_el.ghost_type); UInt nb_facet_per_loc_element = subelement_to_element.getNbComponent(); for (UInt f_in = 0; f_in < nb_facet_per_loc_element; ++f_in) { auto & el = subelement_to_element(loc_el.element, f_in); if (el.type != _not_defined) continue; el.type = facet_type; el.element = current_facet; el.ghost_type = facet_ghost_type; break; } } /// reset connectivity in case a facet was found in /// between ghost and normal elements if (facet_ghost_type != ghost_type) { facet_ghost_type = ghost_type; connectivity_facets = &mesh_accessor.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_accessor.getElementToSubelement( facet_type, facet_ghost_type); } } } } } } // restore the parent of mesh_facet if (mesh_facets_parent) mesh_facets.defineMeshParent(*mesh_facets_parent); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, Array<UInt> & local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array<UInt> & old_nodes_numbers) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map<UInt, UInt> renumbering_map; for (UInt i = 0; i < old_nodes_numbers.size(); ++i) { renumbering_map[old_nodes_numbers(i)] = i; } /// renumber the nodes renumberNodesInConnectivity(local_connectivities, (nb_local_element + nb_ghost_element) * nb_nodes_per_element, renumbering_map); old_nodes_numbers.resize(renumbering_map.size()); for (auto & renumber_pair : renumbering_map) { old_nodes_numbers(renumber_pair.second) = renumber_pair.first; } renumbering_map.clear(); MeshAccessor mesh_accessor(mesh); /// copy the renumbered connectivity to the right place auto & local_conn = mesh_accessor.getConnectivity(type); local_conn.resize(nb_local_element); memcpy(local_conn.storage(), local_connectivities.storage(), nb_local_element * nb_nodes_per_element * sizeof(UInt)); auto & ghost_conn = mesh_accessor.getConnectivity(type, _ghost); ghost_conn.resize(nb_ghost_element); std::memcpy(ghost_conn.storage(), local_connectivities.storage() + nb_local_element * nb_nodes_per_element, nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); auto & ghost_counter = mesh_accessor.getGhostsCounters(type, _ghost); ghost_counter.resize(nb_ghost_element, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity( Array<UInt> & list_nodes, UInt nb_nodes, std::map<UInt, UInt> & renumbering_map) { AKANTU_DEBUG_IN(); UInt * connectivity = list_nodes.storage(); UInt new_node_num = renumbering_map.size(); for (UInt n = 0; n < nb_nodes; ++n, ++connectivity) { UInt & node = *connectivity; auto it = renumbering_map.find(node); if (it == renumbering_map.end()) { UInt old_node = node; renumbering_map[old_node] = new_node_num; node = new_node_num; ++new_node_num; } else { node = it->second; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::purifyMesh(Mesh & mesh) { AKANTU_DEBUG_IN(); std::map<UInt, UInt> renumbering_map; RemovedNodesEvent remove_nodes(mesh); Array<UInt> & nodes_removed = remove_nodes.getList(); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { auto ghost_type = (GhostType)gt; Mesh::type_iterator it = mesh.firstType(_all_dimensions, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != end; ++it) { ElementType type(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity.size()); renumberNodesInConnectivity( connectivity, nb_element * nb_nodes_per_element, renumbering_map); } } Array<UInt> & new_numbering = remove_nodes.getNewNumbering(); std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); auto it = renumbering_map.begin(); auto end = renumbering_map.end(); for (; it != end; ++it) { new_numbering(it->first) = it->second; } for (UInt i = 0; i < new_numbering.size(); ++i) { if (new_numbering(i) == UInt(-1)) nodes_removed.push_back(i); } mesh.sendEvent(remove_nodes); AKANTU_DEBUG_OUT(); } #if defined(AKANTU_COHESIVE_ELEMENT) /* -------------------------------------------------------------------------- */ UInt MeshUtils::insertCohesiveElements( Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion, Array<UInt> & doubled_nodes, Array<Element> & new_elements, bool only_double_facets) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt elements_to_insert = updateFacetToDouble(mesh_facets, facet_insertion); if (elements_to_insert > 0) { if (spatial_dimension == 1) { doublePointFacet(mesh, mesh_facets, doubled_nodes); } else { doubleFacet(mesh, mesh_facets, spatial_dimension - 1, doubled_nodes, true); findSubfacetToDouble<false>(mesh, mesh_facets); if (spatial_dimension == 2) { doubleSubfacet<2>(mesh, mesh_facets, doubled_nodes); } else if (spatial_dimension == 3) { doubleFacet(mesh, mesh_facets, 1, doubled_nodes, false); findSubfacetToDouble<true>(mesh, mesh_facets); doubleSubfacet<3>(mesh, mesh_facets, doubled_nodes); } } if (!only_double_facets) updateCohesiveData(mesh, mesh_facets, new_elements); } return elements_to_insert; } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doubleNodes(Mesh & mesh, const std::vector<UInt> & old_nodes, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); Array<Real> & position = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt old_nb_nodes = position.size(); UInt new_nb_nodes = old_nb_nodes + old_nodes.size(); UInt old_nb_doubled_nodes = doubled_nodes.size(); UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.size(); position.resize(new_nb_nodes); doubled_nodes.resize(new_nb_doubled_nodes); Array<Real>::iterator<Vector<Real>> position_begin = position.begin(spatial_dimension); for (UInt n = 0; n < old_nodes.size(); ++n) { UInt new_node = old_nb_nodes + n; /// store doubled nodes doubled_nodes(old_nb_doubled_nodes + n, 0) = old_nodes[n]; doubled_nodes(old_nb_doubled_nodes + n, 1) = new_node; /// update position std::copy(position_begin + old_nodes[n], position_begin + old_nodes[n] + 1, position_begin + new_node); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array<UInt> & doubled_nodes, bool facet_mode) { AKANTU_DEBUG_IN(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(facet_dimension, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(facet_dimension, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); const UInt nb_subfacet_per_facet = Mesh::getNbFacetsPerElement(type_facet); GhostType gt_subfacet = _casper; Array<std::vector<Element>> * f_to_subfacet = nullptr; Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); UInt nb_nodes_per_facet = conn_facet.getNbComponent(); UInt old_nb_facet = conn_facet.size(); UInt new_nb_facet = old_nb_facet + nb_facet_to_double; conn_facet.resize(new_nb_facet); subfacet_to_facet.resize(new_nb_facet); UInt new_facet = old_nb_facet - 1; Element new_facet_el{type_facet, 0, gt_facet}; Array<Element>::iterator<Vector<Element>> subfacet_to_facet_begin = subfacet_to_facet.begin(nb_subfacet_per_facet); Array<UInt>::iterator<Vector<UInt>> conn_facet_begin = conn_facet.begin(nb_nodes_per_facet); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); ++new_facet; /// adding a new facet by copying original one /// copy connectivity in new facet std::copy(conn_facet_begin + old_facet, conn_facet_begin + old_facet + 1, conn_facet_begin + new_facet); /// update subfacet_to_facet std::copy(subfacet_to_facet_begin + old_facet, subfacet_to_facet_begin + old_facet + 1, subfacet_to_facet_begin + new_facet); new_facet_el.element = new_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet_per_facet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; f_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, subfacet.ghost_type); } /// update facet_to_subfacet array (*f_to_subfacet)(subfacet.element).push_back(new_facet_el); } } /// update facet_to_subfacet and _segment_3 facets if any if (!facet_mode) { updateSubfacetToFacet(mesh_facets, type_facet, gt_facet, true); updateFacetToSubfacet(mesh_facets, type_facet, gt_facet, true); updateQuadraticSegments<true>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } else updateQuadraticSegments<false>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateFacetToDouble( Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); UInt nb_facets_to_double = 0.; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; const Array<bool> & f_insertion = facet_insertion(type_facet, gt_facet); Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); ElementType el_type = _not_defined; GhostType el_gt = _casper; UInt nb_facet_per_element = 0; Element old_facet_el{type_facet, 0, gt_facet}; Array<Element> * facet_to_element = nullptr; for (UInt f = 0; f < f_insertion.size(); ++f) { if (f_insertion(f) == false) continue; ++nb_facets_to_double; if (element_to_facet(f)[1].type == _not_defined #if defined(AKANTU_COHESIVE_ELEMENT) || element_to_facet(f)[1].kind() == _ek_cohesive #endif ) { AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary"); continue; } f_to_double.push_back(f); UInt new_facet = mesh_facets.getNbElement(type_facet, gt_facet) + f_to_double.size() - 1; old_facet_el.element = f; /// update facet_to_element vector Element & elem_to_update = element_to_facet(f)[1]; UInt el = elem_to_update.element; if (elem_to_update.ghost_type != el_gt || elem_to_update.type != el_type) { el_type = elem_to_update.type; el_gt = elem_to_update.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(el_type, el_gt); nb_facet_per_element = facet_to_element->getNbComponent(); } Element * f_update = std::find(facet_to_element->storage() + el * nb_facet_per_element, facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, old_facet_el); AKANTU_DEBUG_ASSERT( facet_to_element->storage() + el * nb_facet_per_element != facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, "Facet not found"); f_update->element = new_facet; /// update elements connected to facet std::vector<Element> first_facet_list = element_to_facet(f); element_to_facet.push_back(first_facet_list); /// set new and original facets as boundary facets element_to_facet(new_facet)[0] = element_to_facet(new_facet)[1]; element_to_facet(f)[1] = ElementNull; element_to_facet(new_facet)[1] = ElementNull; } } } AKANTU_DEBUG_OUT(); return nb_facets_to_double; } /* -------------------------------------------------------------------------- */ void MeshUtils::resetFacetToDouble(Mesh & mesh_facets) { AKANTU_DEBUG_IN(); for (UInt g = _not_ghost; g <= _ghost; ++g) { auto gt = (GhostType)g; Mesh::type_iterator it = mesh_facets.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh_facets.lastType(_all_dimensions, gt); for (; it != end; ++it) { ElementType type = *it; mesh_facets.getDataPointer<UInt>("facet_to_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "facets_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "elements_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "subfacets_to_subsubfacet_double", type, gt, 1, false); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool subsubfacet_mode> void MeshUtils::findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); GhostType gt_subfacet = _casper; ElementType type_subsubfacet = Mesh::getFacetType(type_subfacet); GhostType gt_subsubfacet = _casper; Array<UInt> * conn_subfacet = nullptr; Array<UInt> * sf_to_double = nullptr; Array<std::vector<Element>> * sf_to_subfacet_double = nullptr; Array<std::vector<Element>> * f_to_subfacet_double = nullptr; Array<std::vector<Element>> * el_to_subfacet_double = nullptr; UInt nb_subfacet = Mesh::getNbFacetsPerElement(type_facet); UInt nb_subsubfacet; UInt nb_nodes_per_sf_el; if (subsubfacet_mode) { nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subsubfacet); nb_subsubfacet = Mesh::getNbFacetsPerElement(type_subfacet); } else nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subfacet); Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array<Element> * subsubfacet_to_subfacet = nullptr; UInt old_nb_facet = subfacet_to_facet.size() - nb_facet_to_double; Element current_facet{type_facet, 0, gt_facet}; std::vector<Element> element_list; std::vector<Element> facet_list; std::vector<Element> * subfacet_list; if (subsubfacet_mode) subfacet_list = new std::vector<Element>; /// map to filter subfacets Array<std::vector<Element>> * facet_to_subfacet = nullptr; /// this is used to make sure that both new and old facets are /// checked UInt facets[2]; /// loop on every facet for (UInt f_index = 0; f_index < 2; ++f_index) { for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { facets[bool(f_index)] = f_to_double(facet); facets[!bool(f_index)] = old_nb_facet + facet; UInt old_facet = facets[0]; UInt new_facet = facets[1]; Element & starting_element = element_to_facet(new_facet)[0]; current_facet.element = old_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; if (subsubfacet_mode) { subsubfacet_to_subfacet = &mesh_facets.getSubelementToElement( type_subfacet, gt_subfacet); } else { conn_subfacet = &mesh_facets.getConnectivity(type_subfacet, gt_subfacet); sf_to_double = &mesh_facets.getData<UInt>( "facet_to_double", type_subfacet, gt_subfacet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subfacet, gt_subfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, gt_subfacet); } } if (subsubfacet_mode) { /// loop on every subsubfacet for (UInt ssf = 0; ssf < nb_subsubfacet; ++ssf) { Element & subsubfacet = (*subsubfacet_to_subfacet)(subfacet.element, ssf); if (subsubfacet == ElementNull) continue; if (gt_subsubfacet != subsubfacet.ghost_type) { gt_subsubfacet = subsubfacet.ghost_type; conn_subfacet = &mesh_facets.getConnectivity(type_subsubfacet, gt_subsubfacet); sf_to_double = &mesh_facets.getData<UInt>( "facet_to_double", type_subsubfacet, gt_subsubfacet); sf_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subsubfacet, gt_subsubfacet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subsubfacet, gt_subsubfacet); el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subsubfacet, gt_subsubfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subsubfacet, gt_subsubfacet); } UInt global_ssf = subsubfacet.element; Vector<UInt> subsubfacet_connectivity( conn_subfacet->storage() + global_ssf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subsubfacet is to be doubled if (findElementsAroundSubfacet<true>( mesh, mesh_facets, starting_element, current_facet, subsubfacet_connectivity, element_list, facet_list, subfacet_list) == false && removeElementsInVector(*subfacet_list, (*facet_to_subfacet)(global_ssf)) == false) { sf_to_double->push_back(global_ssf); sf_to_subfacet_double->push_back(*subfacet_list); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } else { const UInt global_sf = subfacet.element; Vector<UInt> subfacet_connectivity( conn_subfacet->storage() + global_sf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subfacet is to be doubled if (findElementsAroundSubfacet<false>( mesh, mesh_facets, starting_element, current_facet, subfacet_connectivity, element_list, facet_list) == false && removeElementsInVector( facet_list, (*facet_to_subfacet)(global_sf)) == false) { sf_to_double->push_back(global_sf); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } } } if (subsubfacet_mode) delete subfacet_list; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array<Element> & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; MeshAccessor mesh_facets_accessor(mesh_facets); for (auto gt_facet : ghost_types) { for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); auto & facet_to_coh_element = mesh_facets_accessor.getSubelementToElement(type_cohesive, gt_facet); auto & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); auto & conn_cohesive = mesh.getConnectivity(type_cohesive, gt_facet); UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); UInt old_nb_cohesive_elements = conn_cohesive.size(); UInt new_nb_cohesive_elements = conn_cohesive.size() + nb_facet_to_double; UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; facet_to_coh_element.resize(new_nb_cohesive_elements); conn_cohesive.resize(new_nb_cohesive_elements); UInt new_elements_old_size = new_elements.size(); new_elements.resize(new_elements_old_size + nb_facet_to_double); Element c_element{type_cohesive, 0, gt_facet}; Element f_element{type_facet, 0, gt_facet}; UInt facets[2]; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { /// (in 3D cohesive elements connectivity is inverted) facets[third_dimension] = f_to_double(facet); facets[!third_dimension] = old_nb_facet + facet; UInt cohesive_element = old_nb_cohesive_elements + facet; /// store doubled facets f_element.element = facets[0]; facet_to_coh_element(cohesive_element, 0) = f_element; f_element.element = facets[1]; facet_to_coh_element(cohesive_element, 1) = f_element; /// modify cohesive elements' connectivity for (UInt n = 0; n < nb_nodes_per_facet; ++n) { conn_cohesive(cohesive_element, n) = conn_facet(facets[0], n); conn_cohesive(cohesive_element, n + nb_nodes_per_facet) = conn_facet(facets[1], n); } /// update element_to_facet vectors c_element.element = cohesive_element; element_to_facet(facets[0])[1] = c_element; element_to_facet(facets[1])[1] = c_element; /// add cohesive element to the element event list new_elements(new_elements_old_size + facet) = c_element; } } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); if (spatial_dimension != 1) return; Array<Real> & position = mesh.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); const Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; UInt new_nb_facet = element_to_facet.size(); UInt old_nb_nodes = position.size(); UInt new_nb_nodes = old_nb_nodes + nb_facet_to_double; position.resize(new_nb_nodes); conn_facet.resize(new_nb_facet); UInt old_nb_doubled_nodes = doubled_nodes.size(); doubled_nodes.resize(old_nb_doubled_nodes + nb_facet_to_double); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt new_facet = old_nb_facet + facet; ElementType type = element_to_facet(new_facet)[0].type; UInt el = element_to_facet(new_facet)[0].element; GhostType gt = element_to_facet(new_facet)[0].ghost_type; UInt old_node = conn_facet(old_facet); UInt new_node = old_nb_nodes + facet; /// update position position(new_node) = position(old_node); conn_facet(new_facet) = new_node; Array<UInt> & conn_segment = mesh.getConnectivity(type, gt); UInt nb_nodes_per_segment = conn_segment.getNbComponent(); /// update facet connectivity UInt i; for (i = 0; conn_segment(el, i) != old_node && i <= nb_nodes_per_segment; ++i) ; conn_segment(el, i) = new_node; doubled_nodes(old_nb_doubled_nodes + facet, 0) = old_node; doubled_nodes(old_nb_doubled_nodes + facet, 1) = new_node; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_segments> void MeshUtils::updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (type_facet != _segment_3) return; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); UInt old_nb_facet = mesh_facets.getNbElement(type_facet, gt_facet) - nb_facet_to_double; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); /// this ones matter only for segments in 3D Array<std::vector<Element>> * el_to_subfacet_double = nullptr; Array<std::vector<Element>> * f_to_subfacet_double = nullptr; if (third_dim_segments) { el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_facet, gt_facet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_facet, gt_facet); } std::vector<UInt> middle_nodes; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt node = conn_facet(old_facet, 2); if (!mesh.isPureGhostNode(node)) middle_nodes.push_back(node); } UInt n = doubled_nodes.size(); doubleNodes(mesh, middle_nodes, doubled_nodes); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt old_node = conn_facet(old_facet, 2); if (mesh.isPureGhostNode(old_node)) continue; UInt new_node = doubled_nodes(n, 1); UInt new_facet = old_nb_facet + facet; conn_facet(new_facet, 2) = new_node; if (third_dim_segments) { updateElementalConnectivity(mesh_facets, old_node, new_node, element_to_facet(new_facet)); updateElementalConnectivity(mesh, old_node, new_node, (*el_to_subfacet_double)(facet), &(*f_to_subfacet_double)(facet)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_facet(new_facet)); } ++n; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); /// update subfacet_to_facet vector ElementType type_facet = _not_defined; GhostType gt_facet = _casper; Array<Element> * subfacet_to_facet = nullptr; UInt nb_subfacet_per_facet = 0; UInt old_nb_subfacet = mesh_facets.getNbElement(type_subfacet, gt_subfacet) - nb_subfacet_to_double; Array<std::vector<Element>> * facet_list = nullptr; if (facet_mode) facet_list = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); else facet_list = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); Element old_subfacet_el{type_subfacet, 0, gt_subfacet}; Element new_subfacet_el{type_subfacet, 0, gt_subfacet}; for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { old_subfacet_el.element = sf_to_double(sf); new_subfacet_el.element = old_nb_subfacet + sf; for (UInt f = 0; f < (*facet_list)(sf).size(); ++f) { Element & facet = (*facet_list)(sf)[f]; if (facet.type != type_facet || facet.ghost_type != gt_facet) { type_facet = facet.type; gt_facet = facet.ghost_type; subfacet_to_facet = &mesh_facets.getSubelementToElement(type_facet, gt_facet); nb_subfacet_per_facet = subfacet_to_facet->getNbComponent(); } Element * sf_update = std::find( subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet, subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, old_subfacet_el); AKANTU_DEBUG_ASSERT(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet != subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, "Subfacet not found"); *sf_update = new_subfacet_el; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); Array<std::vector<Element>> & facet_to_subfacet = mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); Array<std::vector<Element>> * facet_to_subfacet_double = nullptr; if (facet_mode) { facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); } else { facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); } UInt old_nb_subfacet = facet_to_subfacet.size(); facet_to_subfacet.resize(old_nb_subfacet + nb_subfacet_to_double); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) facet_to_subfacet(old_nb_subfacet + sf) = (*facet_to_subfacet_double)(sf); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MeshUtils::doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_subfacet = *gt; Mesh::type_iterator it = mesh_facets.firstType(0, gt_subfacet); Mesh::type_iterator end = mesh_facets.lastType(0, gt_subfacet); for (; it != end; ++it) { ElementType type_subfacet = *it; Array<UInt> & sf_to_double = mesh_facets.getData<UInt>( "facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); if (nb_subfacet_to_double == 0) continue; AKANTU_DEBUG_ASSERT( type_subfacet == _point_1, "Only _point_1 subfacet doubling is supported at the moment"); Array<UInt> & conn_subfacet = mesh_facets.getConnectivity(type_subfacet, gt_subfacet); UInt old_nb_subfacet = conn_subfacet.size(); UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double; conn_subfacet.resize(new_nb_subfacet); std::vector<UInt> nodes_to_double; UInt old_nb_doubled_nodes = doubled_nodes.size(); /// double nodes for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_subfacet = sf_to_double(sf); nodes_to_double.push_back(conn_subfacet(old_subfacet)); } doubleNodes(mesh, nodes_to_double, doubled_nodes); /// add new nodes in connectivity for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt new_subfacet = old_nb_subfacet + sf; UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); conn_subfacet(new_subfacet) = new_node; } /// update facet and element connectivity Array<std::vector<Element>> & f_to_subfacet_double = mesh_facets.getData<std::vector<Element>>("facets_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element>> & el_to_subfacet_double = mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element>> * sf_to_subfacet_double = nullptr; if (spatial_dimension == 3) sf_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_node = doubled_nodes(old_nb_doubled_nodes + sf, 0); UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); updateElementalConnectivity(mesh, old_node, new_node, el_to_subfacet_double(sf), &f_to_subfacet_double(sf)); updateElementalConnectivity(mesh_facets, old_node, new_node, f_to_subfacet_double(sf)); if (spatial_dimension == 3) updateElementalConnectivity(mesh_facets, old_node, new_node, (*sf_to_subfacet_double)(sf)); } if (spatial_dimension == 2) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, true); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, true); } else if (spatial_dimension == 3) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, false); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::flipFacets( Mesh & mesh_facets, const ElementTypeMapArray<UInt> & global_connectivity, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); /// get global connectivity for local mesh ElementTypeMapArray<UInt> global_connectivity_tmp("global_connectivity_tmp", mesh_facets.getID(), mesh_facets.getMemoryID()); global_connectivity_tmp.initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _ghost_type = gt_facet, _with_nb_nodes_per_element = true, _with_nb_element = true); mesh_facets.getGlobalConnectivity(global_connectivity_tmp); /// loop on every facet for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { auto & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet); const auto & g_connectivity = global_connectivity(type_facet, gt_facet); auto & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet); auto & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); UInt nb_subfacet_per_facet = subfacet_to_facet.getNbComponent(); UInt nb_nodes_per_facet = connectivity.getNbComponent(); UInt nb_facet = connectivity.size(); UInt nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); auto & global_conn_tmp = global_connectivity_tmp(type_facet, gt_facet); auto conn_it = connectivity.begin(nb_nodes_per_facet); auto gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet); auto conn_glob_it = g_connectivity.begin(nb_nodes_per_facet); auto subf_to_f = subfacet_to_facet.begin(nb_subfacet_per_facet); auto * conn_tmp_pointer = new UInt[nb_nodes_per_facet]; Vector<UInt> conn_tmp(conn_tmp_pointer, nb_nodes_per_facet); Element el_tmp; auto * subf_tmp_pointer = new Element[nb_subfacet_per_facet]; Vector<Element> subf_tmp(subf_tmp_pointer, nb_subfacet_per_facet); for (UInt f = 0; f < nb_facet; ++f, ++conn_it, ++gconn_tmp_it, ++subf_to_f, ++conn_glob_it) { Vector<UInt> & gconn_tmp = *gconn_tmp_it; const Vector<UInt> & conn_glob = *conn_glob_it; Vector<UInt> & conn_local = *conn_it; /// skip facet if connectivities are the same if (gconn_tmp == conn_glob) continue; /// re-arrange connectivity conn_tmp = conn_local; UInt * begin = conn_glob.storage(); UInt * end = conn_glob.storage() + nb_nodes_per_facet; for (UInt n = 0; n < nb_nodes_per_facet; ++n) { UInt * new_node = std::find(begin, end, gconn_tmp(n)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; conn_local(new_position) = conn_tmp(n); } /// if 3D, check if facets are just rotated if (spatial_dimension == 3) { /// find first node UInt * new_node = std::find(begin, end, gconn_tmp(0)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; UInt n = 1; /// count how many nodes in the received connectivity follow /// the same order of those in the local connectivity for (; n < nb_nodes_per_P1_facet && gconn_tmp(n) == conn_glob((new_position + n) % nb_nodes_per_P1_facet); ++n) ; /// skip the facet inversion if facet is just rotated if (n == nb_nodes_per_P1_facet) continue; } /// update data to invert facet el_tmp = el_to_f(f)[0]; el_to_f(f)[0] = el_to_f(f)[1]; el_to_f(f)[1] = el_tmp; subf_tmp = (*subf_to_f); (*subf_to_f)(0) = subf_tmp(1); (*subf_to_f)(1) = subf_tmp(0); } delete[] subf_tmp_pointer; delete[] conn_tmp_pointer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::fillElementToSubElementsData(Mesh & mesh) { AKANTU_DEBUG_IN(); if (mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) { AKANTU_DEBUG_INFO("There are not facets, add them in the mesh file or call " "the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray<Real> barycenters("barycenter_tmp", mesh.getID(), mesh.getMemoryID()); barycenters.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = _all_dimensions); // mesh.initElementTypeMapArray(barycenters, spatial_dimension, // _all_dimensions); Element element; for (auto ghost_type : ghost_types) { element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(_all_dimensions, ghost_type)) { element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array<Real> & barycenters_arr = barycenters(type, ghost_type); barycenters_arr.resize(nb_element); auto bary = barycenters_arr.begin(spatial_dimension); auto bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { element.element = el; mesh.getBarycenter(element, *bary); } } } MeshAccessor mesh_accessor(mesh); for (Int sp(spatial_dimension); sp >= 1; --sp) { if (mesh.getNbElement(sp) == 0) continue; for (auto ghost_type : ghost_types) { for (auto & type : mesh.elementTypes(sp, ghost_type)) { mesh_accessor.getSubelementToElement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh_accessor.getSubelementToElement(type, ghost_type).clear(); } for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { mesh_accessor.getElementToSubelement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh.getElementToSubelement(type, ghost_type).clear(); } } CSR<Element> nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (auto ghost_type : ghost_types) { facet_element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { facet_element.type = type; auto & element_to_subelement = mesh.getElementToSubelement(type, ghost_type); const auto & connectivity = mesh.getConnectivity(type, ghost_type); auto fit = connectivity.begin(mesh.getNbNodesPerElement(type)); auto fend = connectivity.end(mesh.getNbNodesPerElement(type)); UInt fid = 0; for (; fit != fend; ++fit, ++fid) { const Vector<UInt> & facet = *fit; facet_element.element = fid; std::map<Element, UInt> element_seen_counter; UInt nb_nodes_per_facet = mesh.getNbNodesPerElement(Mesh::getP1ElementType(type)); for (UInt n(0); n < nb_nodes_per_facet; ++n) { auto eit = nodes_to_elements.begin(facet(n)); auto eend = nodes_to_elements.end(facet(n)); for (; eit != eend; ++eit) { auto & elem = *eit; auto cit = element_seen_counter.find(elem); if (cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } std::vector<Element> connected_elements; auto cit = element_seen_counter.begin(); auto cend = element_seen_counter.end(); for (; cit != cend; ++cit) { if (cit->second == nb_nodes_per_facet) connected_elements.push_back(cit->first); } auto ceit = connected_elements.begin(); auto ceend = connected_elements.end(); for (; ceit != ceend; ++ceit) element_to_subelement(fid).push_back(*ceit); for (UInt ce = 0; ce < connected_elements.size(); ++ce) { Element & elem = connected_elements[ce]; Array<Element> & subelement_to_element = mesh_accessor.getSubelementToElement(elem.type, elem.ghost_type); UInt f(0); for (; f < mesh.getNbFacetsPerElement(elem.type) && subelement_to_element(elem.element, f) != ElementNull; ++f) ; AKANTU_DEBUG_ASSERT( f < mesh.getNbFacetsPerElement(elem.type), "The element " << elem << " seems to have too many facets!! (" << f << " < " << mesh.getNbFacetsPerElement(elem.type) << ")"); subelement_to_element(elem.element, f) = facet_element; } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_points> bool MeshUtils::findElementsAroundSubfacet( const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector<UInt> & subfacet_connectivity, std::vector<Element> & elem_list, std::vector<Element> & facet_list, std::vector<Element> * subfacet_list) { AKANTU_DEBUG_IN(); /// preallocated stuff before starting bool facet_matched = false; elem_list.clear(); facet_list.clear(); if (third_dim_points) subfacet_list->clear(); elem_list.push_back(starting_element); const Array<UInt> * facet_connectivity = nullptr; const Array<UInt> * sf_connectivity = nullptr; const Array<Element> * facet_to_element = nullptr; const Array<Element> * subfacet_to_facet = nullptr; ElementType current_type = _not_defined; GhostType current_ghost_type = _casper; ElementType current_facet_type = _not_defined; GhostType current_facet_ghost_type = _casper; ElementType current_subfacet_type = _not_defined; GhostType current_subfacet_ghost_type = _casper; const Array<std::vector<Element>> * element_to_facet = nullptr; const Element * opposing_el = nullptr; std::queue<Element> elements_to_check; elements_to_check.push(starting_element); /// keep going until there are elements to check while (!elements_to_check.empty()) { /// check current element Element & current_el = elements_to_check.front(); if (current_el.type != current_type || current_el.ghost_type != current_ghost_type) { current_type = current_el.type; current_ghost_type = current_el.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(current_type, current_ghost_type); } /// loop over each facet of the element for (UInt f = 0; f < facet_to_element->getNbComponent(); ++f) { const Element & current_facet = (*facet_to_element)(current_el.element, f); if (current_facet == ElementNull) continue; if (current_facet_type != current_facet.type || current_facet_ghost_type != current_facet.ghost_type) { current_facet_type = current_facet.type; current_facet_ghost_type = current_facet.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( current_facet_type, current_facet_ghost_type); facet_connectivity = &mesh_facets.getConnectivity( current_facet_type, current_facet_ghost_type); if (third_dim_points) subfacet_to_facet = &mesh_facets.getSubelementToElement( current_facet_type, current_facet_ghost_type); } /// check if end facet is reached if (current_facet == end_facet) facet_matched = true; /// add this facet if not already passed if (std::find(facet_list.begin(), facet_list.end(), current_facet) == facet_list.end() && hasElement(*facet_connectivity, current_facet, subfacet_connectivity)) { facet_list.push_back(current_facet); if (third_dim_points) { /// check subfacets for (UInt sf = 0; sf < subfacet_to_facet->getNbComponent(); ++sf) { const Element & current_subfacet = (*subfacet_to_facet)(current_facet.element, sf); if (current_subfacet == ElementNull) continue; if (current_subfacet_type != current_subfacet.type || current_subfacet_ghost_type != current_subfacet.ghost_type) { current_subfacet_type = current_subfacet.type; current_subfacet_ghost_type = current_subfacet.ghost_type; sf_connectivity = &mesh_facets.getConnectivity( current_subfacet_type, current_subfacet_ghost_type); } if (std::find(subfacet_list->begin(), subfacet_list->end(), current_subfacet) == subfacet_list->end() && hasElement(*sf_connectivity, current_subfacet, subfacet_connectivity)) subfacet_list->push_back(current_subfacet); } } } else continue; /// consider opposing element if ((*element_to_facet)(current_facet.element)[0] == current_el) opposing_el = &(*element_to_facet)(current_facet.element)[1]; else opposing_el = &(*element_to_facet)(current_facet.element)[0]; /// skip null elements since they are on a boundary if (*opposing_el == ElementNull) continue; /// skip this element if already added if (std::find(elem_list.begin(), elem_list.end(), *opposing_el) != elem_list.end()) continue; /// only regular elements have to be checked if (opposing_el->kind() == _ek_regular) elements_to_check.push(*opposing_el); elem_list.push_back(*opposing_el); #ifndef AKANTU_NDEBUG const Array<UInt> & conn_elem = mesh.getConnectivity(opposing_el->type, opposing_el->ghost_type); AKANTU_DEBUG_ASSERT( hasElement(conn_elem, *opposing_el, subfacet_connectivity), "Subfacet doesn't belong to this element"); #endif } /// erased checked element from the list elements_to_check.pop(); } AKANTU_DEBUG_OUT(); return facet_matched; } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateLocalMasterGlobalConnectivity(Mesh & mesh, UInt local_nb_new_nodes) { const auto & comm = mesh.getCommunicator(); Int rank = comm.whoAmI(); Int nb_proc = comm.getNbProc(); if (nb_proc == 1) return local_nb_new_nodes; /// resize global ids array Array<UInt> & nodes_global_ids = mesh.getGlobalNodesIds(); UInt old_nb_nodes = mesh.getNbNodes() - local_nb_new_nodes; nodes_global_ids.resize(mesh.getNbNodes()); /// compute the number of global nodes based on the number of old nodes Vector<UInt> old_local_master_nodes(nb_proc); for (UInt n = 0; n < old_nb_nodes; ++n) if (mesh.isLocalOrMasterNode(n)) ++old_local_master_nodes(rank); comm.allGather(old_local_master_nodes); UInt old_global_nodes = std::accumulate(old_local_master_nodes.storage(), old_local_master_nodes.storage() + nb_proc, 0); /// compute amount of local or master doubled nodes Vector<UInt> local_master_nodes(nb_proc); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) if (mesh.isLocalOrMasterNode(n)) ++local_master_nodes(rank); comm.allGather(local_master_nodes); /// update global number of nodes UInt total_nb_new_nodes = std::accumulate( local_master_nodes.storage(), local_master_nodes.storage() + nb_proc, 0); if (total_nb_new_nodes == 0) return 0; /// set global ids of local and master nodes UInt starting_index = std::accumulate(local_master_nodes.storage(), local_master_nodes.storage() + rank, old_global_nodes); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) { nodes_global_ids(n) = starting_index; ++starting_index; } } MeshAccessor mesh_accessor(mesh); mesh_accessor.setNbGlobalNodes(old_global_nodes + total_nb_new_nodes); return total_nb_new_nodes; } /* -------------------------------------------------------------------------- */ void MeshUtils::updateElementalConnectivity( Mesh & mesh, UInt old_node, UInt new_node, const std::vector<Element> & element_list, __attribute__((unused)) const std::vector<Element> * facet_list) { AKANTU_DEBUG_IN(); ElementType el_type = _not_defined; GhostType gt_type = _casper; Array<UInt> * conn_elem = nullptr; #if defined(AKANTU_COHESIVE_ELEMENT) const Array<Element> * cohesive_facets = nullptr; #endif UInt nb_nodes_per_element = 0; UInt * n_update = nullptr; for (UInt el = 0; el < element_list.size(); ++el) { const Element & elem = element_list[el]; if (elem.type == _not_defined) continue; if (elem.type != el_type || elem.ghost_type != gt_type) { el_type = elem.type; gt_type = elem.ghost_type; conn_elem = &mesh.getConnectivity(el_type, gt_type); nb_nodes_per_element = conn_elem->getNbComponent(); #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind() == _ek_cohesive) cohesive_facets = &mesh.getMeshFacets().getSubelementToElement(el_type, gt_type); #endif } #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind() == _ek_cohesive) { AKANTU_DEBUG_ASSERT( facet_list != nullptr, "Provide a facet list in order to update cohesive elements"); /// loop over cohesive element's facets for (UInt f = 0, n = 0; f < 2; ++f, n += nb_nodes_per_element / 2) { const Element & facet = (*cohesive_facets)(elem.element, f); /// skip facets if not present in the list if (std::find(facet_list->begin(), facet_list->end(), facet) == facet_list->end()) continue; n_update = std::find( conn_elem->storage() + elem.element * nb_nodes_per_element + n, conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, "Node not found in current element"); /// update connectivity *n_update = new_node; } } else { #endif n_update = std::find(conn_elem->storage() + elem.element * nb_nodes_per_element, conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, "Node not found in current element"); /// update connectivity *n_update = new_node; #if defined(AKANTU_COHESIVE_ELEMENT) } #endif } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/mesh_utils/mesh_utils.hh b/src/mesh_utils/mesh_utils.hh index f7af08129..51932d972 100644 --- a/src/mesh_utils/mesh_utils.hh +++ b/src/mesh_utils/mesh_utils.hh @@ -1,244 +1,243 @@ /** * @file mesh_utils.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Oct 02 2015 + * @date last modification: Sun Dec 03 2017 * * @brief All mesh utils necessary for various tasks * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_UTILS_HH__ #define __AKANTU_MESH_UTILS_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class MeshUtils { /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// build a CSR<UInt> that contains for each node the linearized number of /// the connected elements of a given spatial dimension // static void buildNode2Elements(const Mesh & mesh, CSR<UInt> & node_to_elem, // UInt spatial_dimension = _all_dimensions); /// build a CSR<Element> that contains for each node the list of connected /// elements of a given spatial dimension static void buildNode2Elements(const Mesh & mesh, CSR<Element> & node_to_elem, UInt spatial_dimension = _all_dimensions); /// build a CSR<UInt> that contains for each node the number of /// the connected elements of a given ElementType static void buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR<UInt> & node_to_elem, const ElementType & type, const GhostType & ghost_type = _not_ghost); /// build the facets elements on the boundaries of a mesh static void buildFacets(Mesh & mesh); /// build all the facets elements: boundary and internals and store them in /// the mesh_facets for element of dimension from_dimension to to_dimension static void buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension); /// build all the facets elements: boundary and internals and store them in /// the mesh_facets static void buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension = 0); /// build facets for a given spatial dimension static void buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension); /// take the local_connectivity array as the array of local and ghost /// connectivity, renumber the nodes and set the connectivity of the mesh static void renumberMeshNodes(Mesh & mesh, Array<UInt> & local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array<UInt> & old_nodes); /// compute pbc pair for a given direction static void computePBCMap(const Mesh & mymesh, const UInt dir, std::map<UInt, UInt> & pbc_pair); /// compute pbc pair for a surface pair static void computePBCMap(const Mesh & mymesh, const std::pair<ID, ID> & surface_pair, std::map<UInt, UInt> & pbc_pair); /// remove not connected nodes /!\ this functions renumbers the nodes. static void purifyMesh(Mesh & mesh); #if defined(AKANTU_COHESIVE_ELEMENT) /// function to insert cohesive elements on the selected facets /// @return number of facets that have been doubled static UInt insertCohesiveElements(Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion, Array<UInt> & doubled_nodes, Array<Element> & new_elements, bool only_double_facets); #endif /// fill the subelement to element and the elements to subelements data static void fillElementToSubElementsData(Mesh & mesh); /// flip facets based on global connectivity static void flipFacets(Mesh & mesh_facets, const ElementTypeMapArray<UInt> & global_connectivity, GhostType gt_facet); /// provide list of elements around a node and check if a given /// facet is reached template <bool third_dim_points> static bool findElementsAroundSubfacet( const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector<UInt> & subfacet_connectivity, std::vector<Element> & elem_list, std::vector<Element> & facet_list, std::vector<Element> * subfacet_list = nullptr); /// function to check if a node belongs to a given element static inline bool hasElement(const Array<UInt> & connectivity, const Element & el, const Vector<UInt> & nodes); /// reset facet_to_double arrays in the Mesh static void resetFacetToDouble(Mesh & mesh_facets); /// associate a node type to each segment in the mesh // static void buildSegmentToNodeType(const Mesh & mesh, Mesh & mesh_facets); /// update local and master global connectivity when new nodes are added static UInt updateLocalMasterGlobalConnectivity(Mesh & mesh, UInt old_nb_nodes); private: /// match pairs that are on the associated pbc's static void matchPBCPairs(const Mesh & mymesh, const UInt dir, Array<UInt> & selected_left, Array<UInt> & selected_right, std::map<UInt, UInt> & pbc_pair); /// function used by all the renumbering functions static void renumberNodesInConnectivity(Array<UInt> & list_nodes, UInt nb_nodes, std::map<UInt, UInt> & renumbering_map); /// update facet_to_subfacet static void updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// update subfacet_to_facet static void updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// function to double a given facet and update the list of doubled /// nodes static void doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array<UInt> & doubled_nodes, bool facet_mode); /// function to double a subfacet given start and end index for /// local facet_to_subfacet vector, and update the list of doubled /// nodes template <UInt spatial_dimension> static void doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes); /// double a node static void doubleNodes(Mesh & mesh, const std::vector<UInt> & old_nodes, Array<UInt> & doubled_nodes); /// fill facet_to_double array in the mesh /// returns the number of facets to be doubled static UInt updateFacetToDouble(Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion); /// find subfacets to be doubled template <bool subsubfacet_mode> static void findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets); /// double facets (points) in 1D static void doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes); #if defined(AKANTU_COHESIVE_ELEMENT) /// update cohesive element data static void updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array<Element> & new_elements); #endif /// update elemental connectivity after doubling a node inline static void updateElementalConnectivity( Mesh & mesh, UInt old_node, UInt new_node, const std::vector<Element> & element_list, const std::vector<Element> * facet_list = nullptr); /// double middle nodes if facets are _segment_3 template <bool third_dim_segments> static void updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array<UInt> & doubled_nodes); /// remove elements on a vector inline static bool removeElementsInVector(const std::vector<Element> & elem_to_remove, std::vector<Element> & elem_list); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "mesh_utils_inline_impl.cc" } // akantu #endif /* __AKANTU_MESH_UTILS_HH__ */ diff --git a/src/mesh_utils/mesh_utils_distribution.cc b/src/mesh_utils/mesh_utils_distribution.cc index c6e00425b..416eb5c45 100644 --- a/src/mesh_utils/mesh_utils_distribution.cc +++ b/src/mesh_utils/mesh_utils_distribution.cc @@ -1,172 +1,174 @@ /** * @file mesh_utils_distribution.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Sun Oct 2 19:23:15 2016 + * @date creation: Tue Nov 08 2016 + * @date last modification: Tue Nov 07 2017 * * @brief Implementation of the methods of mesh utils distribute * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "mesh_utils_distribution.hh" #include "element_info_per_processor.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_accessor.hh" #include "mesh_partition.hh" #include "mesh_utils.hh" #include "node_info_per_processor.hh" #include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { namespace MeshUtilsDistribution { /* ------------------------------------------------------------------------ */ void distributeMeshCentralized(Mesh & mesh, UInt, const MeshPartition & partition) { MeshAccessor mesh_accessor(mesh); ElementSynchronizer & element_synchronizer = mesh_accessor.getElementSynchronizer(); NodeSynchronizer & node_synchronizer = mesh_accessor.getNodeSynchronizer(); const Communicator & comm = element_synchronizer.getCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); mesh_accessor.setNbGlobalNodes(mesh.getNbNodes()); auto & gids = mesh_accessor.getNodesGlobalIds(); if (nb_proc == 1) return; gids.resize(0); mesh.synchronizeGroupNames(); AKANTU_DEBUG_ASSERT( partition.getNbPartition() == nb_proc, "The number of partition does not match the number of processors: " << partition.getNbPartition() << " != " << nb_proc); /** * connectivity and communications scheme construction */ UInt count = 0; /* --- MAIN LOOP ON TYPES --- */ for (auto && type : mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { /// \todo change this ugly way to avoid a problem if an element /// type is present in the mesh but not in the partitions try { partition.getPartition(type, _not_ghost); } catch (...) { continue; } MasterElementInfoPerProc proc_infos(element_synchronizer, count, my_rank, type, partition); proc_infos.synchronizeConnectivities(); proc_infos.synchronizePartitions(); proc_infos.synchronizeTags(); proc_infos.synchronizeGroups(); ++count; } { /// Ending the synchronization of elements by sending a stop message MasterElementInfoPerProc proc_infos(element_synchronizer, count, my_rank, _not_defined, partition); ++count; } /** * Nodes synchronization */ MasterNodeInfoPerProc node_proc_infos(node_synchronizer, count, my_rank); node_proc_infos.synchronizeNodes(); node_proc_infos.synchronizeTypes(); node_proc_infos.synchronizeGroups(); MeshUtils::fillElementToSubElementsData(mesh); mesh_accessor.setDistributed(); AKANTU_DEBUG_OUT(); } /* ------------------------------------------------------------------------ */ void distributeMeshCentralized(Mesh & mesh, UInt root) { MeshAccessor mesh_accessor(mesh); ElementSynchronizer & element_synchronizer = mesh_accessor.getElementSynchronizer(); NodeSynchronizer & node_synchronizer = mesh_accessor.getNodeSynchronizer(); const Communicator & comm = element_synchronizer.getCommunicator(); UInt nb_proc = comm.getNbProc(); mesh_accessor.getNodesGlobalIds().resize(0); if (nb_proc == 1) return; mesh.synchronizeGroupNames(); /** * connectivity and communications scheme construction on distant * processors */ UInt count = 0; bool need_synchronize = true; do { /* --------<<<<-SIZE--------------------------------------------------- */ SlaveElementInfoPerProc proc_infos(element_synchronizer, count, root); need_synchronize = proc_infos.needSynchronize(); if (need_synchronize) { proc_infos.synchronizeConnectivities(); proc_infos.synchronizePartitions(); proc_infos.synchronizeTags(); proc_infos.synchronizeGroups(); } ++count; } while (need_synchronize); /** * Nodes synchronization */ SlaveNodeInfoPerProc node_proc_infos(node_synchronizer, count, root); node_proc_infos.synchronizeNodes(); node_proc_infos.synchronizeTypes(); node_proc_infos.synchronizeGroups(); MeshUtils::fillElementToSubElementsData(mesh); mesh_accessor.setDistributed(); } } // namespace MeshUtilsDistribution } // namespace akantu diff --git a/src/mesh_utils/mesh_utils_distribution.hh b/src/mesh_utils/mesh_utils_distribution.hh index e498a6ae7..82112b2dc 100644 --- a/src/mesh_utils/mesh_utils_distribution.hh +++ b/src/mesh_utils/mesh_utils_distribution.hh @@ -1,54 +1,55 @@ /** * @file mesh_utils_distribution.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Sun Oct 2 19:04:13 2016 + * @date creation: Fri Jun 18 2010 + * @date last modification: Sat Apr 01 2017 * * @brief Mesh utils to distribute a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_UTILS_DISTRIBUTION_HH__ #define __AKANTU_MESH_UTILS_DISTRIBUTION_HH__ namespace akantu { class Mesh; class MeshPartition; } // akantu namespace akantu { namespace MeshUtilsDistribution { /// Master call to distribute a mesh in a centralized manner (the UInt is just /// to avoid some shitty access from the slave...) void distributeMeshCentralized(Mesh & mesh, UInt, const MeshPartition & partition); /// Slave call to distribute a mesh in a centralized manner void distributeMeshCentralized(Mesh & mesh, UInt root); } // MeshUtilsDistribution } // akantu #endif /* __AKANTU_MESH_UTILS_DISTRIBUTION_HH__ */ diff --git a/src/mesh_utils/mesh_utils_inline_impl.cc b/src/mesh_utils/mesh_utils_inline_impl.cc index 4c7c8bf27..0a48d9e57 100644 --- a/src/mesh_utils/mesh_utils_inline_impl.cc +++ b/src/mesh_utils/mesh_utils_inline_impl.cc @@ -1,82 +1,81 @@ /** * @file mesh_utils_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Aug 20 2010 - * @date last modification: Fri Mar 20 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Mesh utils inline functions * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline bool MeshUtils::hasElement(const Array<UInt> & connectivity, const Element & el, const Vector<UInt> & nodes) { UInt nb_nodes_per_element = connectivity.getNbComponent(); const Vector<UInt> el_nodes(connectivity.storage() + el.element * nb_nodes_per_element, nb_nodes_per_element); UInt * el_nodes_end = el_nodes.storage() + nb_nodes_per_element; UInt n = 0; while (n < nodes.size() && std::find(el_nodes.storage(), el_nodes_end, nodes[n]) != el_nodes_end) ++n; return (n == nodes.size()); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ inline bool MeshUtils::removeElementsInVector(const std::vector<Element> & elem_to_remove, std::vector<Element> & elem_list) { if (elem_list.size() <= elem_to_remove.size()) return true; auto el_it = elem_to_remove.begin(); auto el_last = elem_to_remove.end(); std::vector<Element>::iterator el_del; UInt deletions = 0; for (; el_it != el_last; ++el_it) { el_del = std::find(elem_list.begin(), elem_list.end(), *el_it); if (el_del != elem_list.end()) { elem_list.erase(el_del); ++deletions; } } AKANTU_DEBUG_ASSERT(deletions == 0 || deletions == elem_to_remove.size(), "Not all elements have been erased"); return deletions == 0; } diff --git a/src/mesh_utils/mesh_utils_pbc.cc b/src/mesh_utils/mesh_utils_pbc.cc index ac6a05a95..ad44e0ae7 100644 --- a/src/mesh_utils/mesh_utils_pbc.cc +++ b/src/mesh_utils/mesh_utils_pbc.cc @@ -1,300 +1,299 @@ /** * @file mesh_utils_pbc.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Wed Feb 09 2011 - * @date last modification: Tue Sep 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief periodic boundary condition connectivity tweak * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #include "element_group.hh" #include "mesh_accessor.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /// class that sorts a set of nodes of same coordinates in 'dir' direction class CoordinatesComparison { public: CoordinatesComparison(const UInt dimension, const UInt dir_1, const UInt dir_2, Real normalization, Real tolerance, const Array<Real> & coords) : dim(dimension), dir_1(dir_1), dir_2(dir_2), normalization(normalization), tolerance(tolerance), coords_it(coords.begin(dim)) {} // answers the question whether n2 is larger or equal to n1 bool operator()(const UInt n1, const UInt n2) { Vector<Real> coords_n1 = coords_it[n1]; Vector<Real> coords_n2 = coords_it[n2]; return this->operator()(coords_n1, coords_n2); } bool operator()(const Vector<Real> & coords_n1, const Vector<Real> & coords_n2) { Real diff = coords_n1(dir_1) - coords_n2(dir_1); ; if (dim == 2 || std::abs(diff) / normalization > tolerance) return diff > 0. ? false : true; else if (dim > 2) { diff = coords_n1(dir_2) - coords_n2(dir_2); ; return diff > 0 ? false : true; } return true; } private: UInt dim; UInt dir_1; UInt dir_2; Real normalization; Real tolerance; const Array<Real>::const_vector_iterator coords_it; }; /* -------------------------------------------------------------------------- */ void MeshUtils::computePBCMap(const Mesh & mesh, const UInt dir, std::map<UInt, UInt> & pbc_pair) { Array<UInt> selected_left; Array<UInt> selected_right; const UInt dim = mesh.getSpatialDimension(); auto it = mesh.getNodes().begin(dim); auto end = mesh.getNodes().end(dim); if (dim <= dir) return; const Vector<Real> & lower_bounds = mesh.getLowerBounds(); const Vector<Real> & upper_bounds = mesh.getUpperBounds(); AKANTU_DEBUG_INFO("min " << lower_bounds(dir)); AKANTU_DEBUG_INFO("max " << upper_bounds(dir)); for (UInt node = 0; it != end; ++it, ++node) { const Vector<Real> & coords = *it; AKANTU_DEBUG_TRACE("treating " << coords(dir)); if (Math::are_float_equal(coords(dir), lower_bounds(dir))) { AKANTU_DEBUG_TRACE("pushing node " << node << " on the left side"); selected_left.push_back(node); } else if (Math::are_float_equal(coords(dir), upper_bounds(dir))) { selected_right.push_back(node); AKANTU_DEBUG_TRACE("pushing node " << node << " on the right side"); } } AKANTU_DEBUG_INFO("found " << selected_left.size() << " and " << selected_right.size() << " nodes at each boundary for direction " << dir); // match pairs MeshUtils::matchPBCPairs(mesh, dir, selected_left, selected_right, pbc_pair); } /* -------------------------------------------------------------------------- */ void MeshUtils::computePBCMap(const Mesh & mesh, const std::pair<ID, ID> & surface_pair, std::map<UInt, UInt> & pbc_pair) { Array<UInt> selected_first; Array<UInt> selected_second; // find nodes on surfaces const ElementGroup & first_surf = mesh.getElementGroup(surface_pair.first); const ElementGroup & second_surf = mesh.getElementGroup(surface_pair.second); // if this surface pair is not on this proc if (first_surf.getNbNodes() == 0 || second_surf.getNbNodes() == 0) { AKANTU_DEBUG_WARNING("computePBCMap has at least one surface without any " "nodes. I will ignore it."); return; } // copy nodes from element group selected_first.copy(first_surf.getNodeGroup().getNodes()); selected_second.copy(second_surf.getNodeGroup().getNodes()); // coordinates const Array<Real> & coords = mesh.getNodes(); const UInt dim = mesh.getSpatialDimension(); // variables to find min and max of surfaces Real first_max[3], first_min[3]; Real second_max[3], second_min[3]; for (UInt i = 0; i < dim; ++i) { first_min[i] = std::numeric_limits<Real>::max(); second_min[i] = std::numeric_limits<Real>::max(); first_max[i] = -std::numeric_limits<Real>::max(); second_max[i] = -std::numeric_limits<Real>::max(); } // find min and max of surface nodes for (auto it = selected_first.begin(); it != selected_first.end(); ++it) { for (UInt i = 0; i < dim; ++i) { if (first_min[i] > coords(*it, i)) first_min[i] = coords(*it, i); if (first_max[i] < coords(*it, i)) first_max[i] = coords(*it, i); } } for (auto it = selected_second.begin(); it != selected_second.end(); ++it) { for (UInt i = 0; i < dim; ++i) { if (second_min[i] > coords(*it, i)) second_min[i] = coords(*it, i); if (second_max[i] < coords(*it, i)) second_max[i] = coords(*it, i); } } // find direction of pbc Int first_dir = -1; #ifndef AKANTU_NDEBUG Int second_dir = -2; #endif for (UInt i = 0; i < dim; ++i) { if (Math::are_float_equal(first_min[i], first_max[i])) { first_dir = i; } #ifndef AKANTU_NDEBUG if (Math::are_float_equal(second_min[i], second_max[i])) { second_dir = i; } #endif } AKANTU_DEBUG_ASSERT(first_dir == second_dir, "Surface pair has not same direction. Surface " << surface_pair.first << " dir=" << first_dir << " ; Surface " << surface_pair.second << " dir=" << second_dir); UInt dir = first_dir; // match pairs if (first_min[dir] < second_min[dir]) MeshUtils::matchPBCPairs(mesh, dir, selected_first, selected_second, pbc_pair); else MeshUtils::matchPBCPairs(mesh, dir, selected_second, selected_first, pbc_pair); } /* -------------------------------------------------------------------------- */ void MeshUtils::matchPBCPairs(const Mesh & mesh, const UInt dir, Array<UInt> & selected_left, Array<UInt> & selected_right, std::map<UInt, UInt> & pbc_pair) { // tolerance is that large because most meshers generate points coordinates // with single precision only (it is the case of GMSH for instance) Real tolerance = 1e-7; const UInt dim = mesh.getSpatialDimension(); Real normalization = mesh.getUpperBounds()(dir) - mesh.getLowerBounds()(dir); AKANTU_DEBUG_ASSERT(std::abs(normalization) > Math::getTolerance(), "In matchPBCPairs: The normalization is zero. " << "Did you compute the bounding box of the mesh?"); auto odir_1 = UInt(-1), odir_2 = UInt(-1); if (dim == 3) { if (dir == _x) { odir_1 = _y; odir_2 = _z; } else if (dir == _y) { odir_1 = _x; odir_2 = _z; } else if (dir == _z) { odir_1 = _x; odir_2 = _y; } } else if (dim == 2) { if (dir == _x) { odir_1 = _y; } else if (dir == _y) { odir_1 = _x; } } CoordinatesComparison compare_nodes(dim, odir_1, odir_2, normalization, tolerance, mesh.getNodes()); std::sort(selected_left.begin(), selected_left.end(), compare_nodes); std::sort(selected_right.begin(), selected_right.end(), compare_nodes); auto it_left = selected_left.begin(); auto end_left = selected_left.end(); auto it_right = selected_right.begin(); auto end_right = selected_right.end(); auto nit = mesh.getNodes().begin(dim); while ((it_left != end_left) && (it_right != end_right)) { UInt i1 = *it_left; UInt i2 = *it_right; Vector<Real> coords1 = nit[i1]; Vector<Real> coords2 = nit[i2]; AKANTU_DEBUG_TRACE("do I pair? " << i1 << "(" << coords1 << ") with" << i2 << "(" << coords2 << ") in direction " << dir); Real dx = 0.0; Real dy = 0.0; if (dim >= 2) dx = coords1(odir_1) - coords2(odir_1); if (dim == 3) dy = coords1(odir_2) - coords2(odir_2); if (std::abs(dx * dx + dy * dy) / normalization < tolerance) { // then i match these pairs if (pbc_pair.count(i2)) { i2 = pbc_pair[i2]; } pbc_pair[i1] = i2; AKANTU_DEBUG_TRACE("pairing " << i1 << "(" << coords1 << ") with" << i2 << "(" << coords2 << ") in direction " << dir); ++it_left; ++it_right; } else if (compare_nodes(coords1, coords2)) { ++it_left; } else { ++it_right; } } AKANTU_DEBUG_INFO("found " << pbc_pair.size() << " pairs for direction " << dir); } } // akantu diff --git a/src/model/boundary_condition.hh b/src/model/boundary_condition.hh index dd7775b2f..82a5b154b 100644 --- a/src/model/boundary_condition.hh +++ b/src/model/boundary_condition.hh @@ -1,101 +1,101 @@ /** * @file boundary_condition.hh * * @author Dana Christen <dana.christen@gmail.com> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Dec 18 2015 + * @date last modification: Wed Jan 31 2018 * * @brief XXX * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_HH__ #define __AKANTU_BOUNDARY_CONDITION_HH__ #include "aka_common.hh" #include "boundary_condition_functor.hh" #include "fe_engine.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ namespace akantu { template <class ModelType> class BoundaryCondition { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ private: /* ------------------------------------------------------------------------ */ /* Constructors / Destructors / Initializers */ /* ------------------------------------------------------------------------ */ public: BoundaryCondition() : model(nullptr) {} /// Initialize the boundary conditions void initBC(ModelType & ptr, Array<Real> & primal, Array<Real> & dual); void initBC(ModelType & ptr, Array<Real> & primal, Array<Real> & primal_increment, Array<Real> & dual); /* ------------------------------------------------------------------------ */ /* Methods and accessors */ /* ------------------------------------------------------------------------ */ public: // inline void initBoundaryCondition(); template <typename FunctorType> /// Apply the boundary conditions inline void applyBC(const FunctorType & func); template <class FunctorType> inline void applyBC(const FunctorType & func, const std::string & group_name); template <class FunctorType> inline void applyBC(const FunctorType & func, const ElementGroup & element_group); AKANTU_GET_MACRO_NOT_CONST(Model, *model, ModelType &); AKANTU_GET_MACRO_NOT_CONST(Primal, *primal, Array<Real> &); AKANTU_GET_MACRO_NOT_CONST(Dual, *dual, Array<Real> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: template <class FunctorType, BC::Functor::Type type = FunctorType::type> struct TemplateFunctionWrapper; private: ModelType * model; Array<Real> * primal{nullptr}; Array<Real> * dual{nullptr}; Array<Real> * primal_increment{nullptr}; }; } // akantu #include "boundary_condition_tmpl.hh" #endif /* __AKANTU_BOUNDARY_CONDITION_HH__ */ diff --git a/src/model/boundary_condition_functor.hh b/src/model/boundary_condition_functor.hh index 84cc245e3..4c54b5b09 100644 --- a/src/model/boundary_condition_functor.hh +++ b/src/model/boundary_condition_functor.hh @@ -1,217 +1,217 @@ /** * @file boundary_condition_functor.hh * * @author Dana Christen <dana.christen@gmail.com> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri May 03 2013 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Definitions of the functors to apply boundary conditions * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "fe_engine.hh" #include "integration_point.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ #define __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ namespace BC { using Axis = ::akantu::SpacialDirection; struct Functor { enum Type { _dirichlet, _neumann }; }; /* ------------------------------------------------------------------------ */ /* Dirichlet */ /* ------------------------------------------------------------------------ */ namespace Dirichlet { /* ---------------------------------------------------------------------- */ class DirichletFunctor : public Functor { protected: DirichletFunctor() = default; explicit DirichletFunctor(Axis ax) : axis(ax) {} public: void operator()(__attribute__((unused)) UInt node, __attribute__((unused)) Vector<bool> & flags, __attribute__((unused)) Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { AKANTU_TO_IMPLEMENT(); } public: static const Type type = _dirichlet; protected: Axis axis{_x}; }; /* ---------------------------------------------------------------------- */ class FlagOnly : public DirichletFunctor { public: explicit FlagOnly(Axis ax = _x) : DirichletFunctor(ax) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; }; /* ---------------------------------------------------------------------- */ class FreeBoundary : public DirichletFunctor { public: explicit FreeBoundary(Axis ax = _x) : DirichletFunctor(ax) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; }; /* ---------------------------------------------------------------------- */ class FixedValue : public DirichletFunctor { public: FixedValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; protected: Real value; }; /* ---------------------------------------------------------------------- */ class IncrementValue : public DirichletFunctor { public: IncrementValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; inline void setIncrement(Real val) { this->value = val; } protected: Real value; }; /* ---------------------------------------------------------------------- */ class Increment : public DirichletFunctor { public: explicit Increment(const Vector<Real> & val) : DirichletFunctor(_x), value(val) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; inline void setIncrement(const Vector<Real> & val) { this->value = val; } protected: Vector<Real> value; }; } // end namespace Dirichlet /* ------------------------------------------------------------------------ */ /* Neumann */ /* ------------------------------------------------------------------------ */ namespace Neumann { /* ---------------------------------------------------------------------- */ class NeumannFunctor : public Functor { protected: NeumannFunctor() = default; public: virtual void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const = 0; virtual ~NeumannFunctor() = default; public: static const Type type = _neumann; }; /* ---------------------------------------------------------------------- */ class FromHigherDim : public NeumannFunctor { public: explicit FromHigherDim(const Matrix<Real> & mat) : bc_data(mat) {} ~FromHigherDim() override = default; public: inline void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const override; protected: Matrix<Real> bc_data; }; /* ---------------------------------------------------------------------- */ class FromSameDim : public NeumannFunctor { public: explicit FromSameDim(const Vector<Real> & vec) : bc_data(vec) {} ~FromSameDim() override = default; public: inline void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const override; protected: Vector<Real> bc_data; }; /* ---------------------------------------------------------------------- */ class FreeBoundary : public NeumannFunctor { public: inline void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const override; }; } // end namespace Neumann } // end namespace BC } // akantu #include "boundary_condition_functor_inline_impl.cc" #endif /* __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ */ diff --git a/src/model/boundary_condition_functor_inline_impl.cc b/src/model/boundary_condition_functor_inline_impl.cc index abe306794..41a7d2b87 100644 --- a/src/model/boundary_condition_functor_inline_impl.cc +++ b/src/model/boundary_condition_functor_inline_impl.cc @@ -1,156 +1,158 @@ /** * @file boundary_condition_functor_inline_impl.cc * * @author Dana Christen <dana.christen@gmail.com> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri May 03 2013 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Mon Feb 19 2018 * * @brief implementation of the BC::Functors * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "boundary_condition_functor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__ #define __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__ /* -------------------------------------------------------------------------- */ #define DIRICHLET_SANITY_CHECK \ AKANTU_DEBUG_ASSERT( \ coord.size() <= flags.size(), \ "The coordinates and flags vectors given to the boundary" \ << " condition functor have different sizes!"); \ AKANTU_DEBUG_ASSERT( \ primal.size() <= coord.size(), \ "The primal vector and coordinates vector given" \ << " to the boundary condition functor have different sizes!"); #define NEUMANN_SANITY_CHECK \ AKANTU_DEBUG_ASSERT( \ coord.size() <= normals.size(), \ "The coordinates and normals vectors given to the" \ << " boundary condition functor have different sizes!"); \ AKANTU_DEBUG_ASSERT( \ dual.size() <= coord.size(), \ "The dual vector and coordinates vector given to" \ << " the boundary condition functor have different sizes!"); namespace akantu { namespace BC { namespace Dirichlet { /* ---------------------------------------------------------------------- */ inline void FlagOnly:: operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, __attribute__((unused)) Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = true; } /* ---------------------------------------------------------------------- */ inline void FreeBoundary:: operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, __attribute__((unused)) Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = false; } /* ---------------------------------------------------------------------- */ inline void FixedValue::operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = true; primal(this->axis) = value; } /* ---------------------------------------------------------------------- */ inline void IncrementValue::operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = true; primal(this->axis) += value; } /* ---------------------------------------------------------------------- */ inline void Increment::operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags.set(true); primal += value; } } // end namespace Dirichlet /* ------------------------------------------------------------------------ */ /* Neumann */ /* ------------------------------------------------------------------------ */ namespace Neumann { /* ---------------------------------------------------------------------- */ inline void FreeBoundary:: operator()(__attribute__((unused)) const IntegrationPoint & quad_point, Vector<Real> & dual, __attribute__((unused)) const Vector<Real> & coord, __attribute__((unused)) const Vector<Real> & normals) const { for (UInt i(0); i < dual.size(); ++i) { dual(i) = 0.0; } } /* ---------------------------------------------------------------------- */ inline void FromHigherDim::operator()(__attribute__((unused)) const IntegrationPoint & quad_point, Vector<Real> & dual, __attribute__((unused)) const Vector<Real> & coord, const Vector<Real> & normals) const { dual.mul<false>(this->bc_data, normals); } /* ---------------------------------------------------------------------- */ inline void FromSameDim:: operator()(__attribute__((unused)) const IntegrationPoint & quad_point, Vector<Real> & dual, __attribute__((unused)) const Vector<Real> & coord, __attribute__((unused)) const Vector<Real> & normals) const { dual = this->bc_data; } } // namespace Neumann } // namespace BC } // namespace akantu #endif /* __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__ */ diff --git a/src/model/boundary_condition_python_functor.cc b/src/model/boundary_condition_python_functor.cc index edc531d6f..d1c42d775 100644 --- a/src/model/boundary_condition_python_functor.cc +++ b/src/model/boundary_condition_python_functor.cc @@ -1,57 +1,57 @@ /** * @file boundary_condition_python_functor.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Wed Aug 31 2011 - * @date last modification: Fri Nov 13 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Interface for BC::Functor written in python * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition_python_functor.hh" /* -------------------------------------------------------------------------- */ namespace akantu { namespace BC { void PythonFunctorDirichlet::operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const { this->callFunctor<void>("operator", node, flags, primal, coord); } void PythonFunctorNeumann::operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const { this->callFunctor<void>("operator", quad_point, dual, coord, normals); } } // end namespace BC } // akantu diff --git a/src/model/boundary_condition_python_functor.hh b/src/model/boundary_condition_python_functor.hh index da7e44410..2380f5052 100644 --- a/src/model/boundary_condition_python_functor.hh +++ b/src/model/boundary_condition_python_functor.hh @@ -1,116 +1,117 @@ /** * @file boundary_condition_python_functor.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Fri Nov 13 2015 + * @date last modification: Wed Jan 31 2018 * * @brief interface for BC::Functor writen in python * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "boundary_condition_functor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_PYTHON_FUNCTOR_HH__ #define __AKANTU_BOUNDARY_CONDITION_PYTHON_FUNCTOR_HH__ /* -------------------------------------------------------------------------- */ #include "boundary_condition_functor.hh" #include "python_functor.hh" /* -------------------------------------------------------------------------- */ namespace akantu { namespace BC { class PythonFunctorDirichlet : public PythonFunctor, public Functor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PythonFunctorDirichlet(PyObject * obj) : PythonFunctor(obj) {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: static const Type type = _dirichlet; }; /* -------------------------------------------------------------------------- */ class PythonFunctorNeumann : public PythonFunctor, public Functor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PythonFunctorNeumann(PyObject * obj) : PythonFunctor(obj) {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: static const Type type = _neumann; }; } // end namespace BC } // akantu #endif /* __AKANTU_BOUNDARY_CONDITION_PYTHON_FUNCTOR_HH__ */ diff --git a/src/model/boundary_condition_tmpl.hh b/src/model/boundary_condition_tmpl.hh index bb4c58039..f45d2ac88 100644 --- a/src/model/boundary_condition_tmpl.hh +++ b/src/model/boundary_condition_tmpl.hh @@ -1,256 +1,256 @@ /** * @file boundary_condition_tmpl.hh * * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri May 03 2013 - * @date last modification: Fri Oct 16 2015 + * @date last modification: Tue Feb 20 2018 * * @brief implementation of the applyBC * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "element_group.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_TMPL_HH__ #define __AKANTU_BOUNDARY_CONDITION_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename ModelType> void BoundaryCondition<ModelType>::initBC(ModelType & model, Array<Real> & primal, Array<Real> & dual) { this->model = &model; this->primal = &primal; this->dual = &dual; } /* -------------------------------------------------------------------------- */ template <typename ModelType> void BoundaryCondition<ModelType>::initBC(ModelType & model, Array<Real> & primal, Array<Real> & primal_increment, Array<Real> & dual) { this->initBC(model, primal, dual); this->primal_increment = &primal_increment; } /* -------------------------------------------------------------------------- */ /* Partial specialization for DIRICHLET functors */ template <typename ModelType> template <typename FunctorType> struct BoundaryCondition<ModelType>::TemplateFunctionWrapper< FunctorType, BC::Functor::_dirichlet> { static inline void applyBC(const FunctorType & func, const ElementGroup & group, BoundaryCondition<ModelType> & bc_instance) { auto & model = bc_instance.getModel(); auto & primal = bc_instance.getPrimal(); const auto & coords = model.getMesh().getNodes(); auto & boundary_flags = model.getBlockedDOFs(); UInt dim = model.getMesh().getSpatialDimension(); auto primal_iter = primal.begin(primal.getNbComponent()); auto coords_iter = coords.begin(dim); auto flags_iter = boundary_flags.begin(boundary_flags.getNbComponent()); for (auto n : group.getNodeGroup()) { Vector<bool> flag(flags_iter[n]); Vector<Real> primal(primal_iter[n]); Vector<Real> coords(coords_iter[n]); func(n, flag, primal, coords); } } }; /* -------------------------------------------------------------------------- */ /* Partial specialization for NEUMANN functors */ template <typename ModelType> template <typename FunctorType> struct BoundaryCondition<ModelType>::TemplateFunctionWrapper< FunctorType, BC::Functor::_neumann> { static inline void applyBC(const FunctorType & func, const ElementGroup & group, BoundaryCondition<ModelType> & bc_instance) { UInt dim = bc_instance.getModel().getSpatialDimension(); switch (dim) { case 1: { AKANTU_TO_IMPLEMENT(); break; } case 2: case 3: { applyBC(func, group, bc_instance, _not_ghost); applyBC(func, group, bc_instance, _ghost); break; } } } static inline void applyBC(const FunctorType & func, const ElementGroup & group, BoundaryCondition<ModelType> & bc_instance, GhostType ghost_type) { auto & model = bc_instance.getModel(); auto & dual = bc_instance.getDual(); const auto & mesh = model.getMesh(); const auto & nodes_coords = mesh.getNodes(); const auto & fem_boundary = model.getFEEngineBoundary(); UInt dim = model.getSpatialDimension(); UInt nb_degree_of_freedom = dual.getNbComponent(); IntegrationPoint quad_point; quad_point.ghost_type = ghost_type; // Loop over the boundary element types for (auto && type : group.elementTypes(dim - 1, ghost_type)) { const auto & element_ids = group.getElements(type, ghost_type); UInt nb_quad_points = fem_boundary.getNbIntegrationPoints(type, ghost_type); UInt nb_elements = element_ids.size(); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); Array<Real> * dual_before_integ = new Array<Real>( nb_elements * nb_quad_points, nb_degree_of_freedom, 0.); Array<Real> * quad_coords = new Array<Real>(nb_elements * nb_quad_points, dim); const auto & normals_on_quad = fem_boundary.getNormalsOnIntegrationPoints(type, ghost_type); fem_boundary.interpolateOnIntegrationPoints( nodes_coords, *quad_coords, dim, type, ghost_type, element_ids); auto normals_begin = normals_on_quad.begin(dim); decltype(normals_begin) normals_iter; auto quad_coords_iter = quad_coords->begin(dim); auto dual_iter = dual_before_integ->begin(nb_degree_of_freedom); quad_point.type = type; for (auto el : element_ids) { quad_point.element = el; normals_iter = normals_begin + el * nb_quad_points; for (auto && q : arange(nb_quad_points)) { quad_point.num_point = q; func(quad_point, *dual_iter, *quad_coords_iter, *normals_iter); ++dual_iter; ++quad_coords_iter; ++normals_iter; } } delete quad_coords; /* -------------------------------------------------------------------- */ // Initialization of iterators auto dual_iter_mat = dual_before_integ->begin(nb_degree_of_freedom, 1); auto shapes_iter_begin = fem_boundary.getShapes(type, ghost_type) .begin(1, nb_nodes_per_element); Array<Real> * dual_by_shapes = new Array<Real>(nb_elements * nb_quad_points, nb_degree_of_freedom * nb_nodes_per_element); auto dual_by_shapes_iter = dual_by_shapes->begin(nb_degree_of_freedom, nb_nodes_per_element); /* -------------------------------------------------------------------- */ // Loop computing dual x shapes for (auto el : element_ids) { auto shapes_iter = shapes_iter_begin + el * nb_quad_points; for (UInt q(0); q < nb_quad_points; ++q, ++dual_iter_mat, ++dual_by_shapes_iter, ++shapes_iter) { dual_by_shapes_iter->template mul<false, false>(*dual_iter_mat, *shapes_iter); } } delete dual_before_integ; Array<Real> * dual_by_shapes_integ = new Array<Real>( nb_elements, nb_degree_of_freedom * nb_nodes_per_element); fem_boundary.integrate(*dual_by_shapes, *dual_by_shapes_integ, nb_degree_of_freedom * nb_nodes_per_element, type, ghost_type, element_ids); delete dual_by_shapes; // assemble the result into force vector model.getDOFManager().assembleElementalArrayLocalArray( *dual_by_shapes_integ, dual, type, ghost_type, 1., element_ids); delete dual_by_shapes_integ; } } }; /* -------------------------------------------------------------------------- */ template <typename ModelType> template <typename FunctorType> inline void BoundaryCondition<ModelType>::applyBC(const FunctorType & func) { auto bit = model->getMesh().getGroupManager().element_group_begin(); auto bend = model->getMesh().getGroupManager().element_group_end(); for (; bit != bend; ++bit) applyBC(func, *bit); } /* -------------------------------------------------------------------------- */ template <typename ModelType> template <typename FunctorType> inline void BoundaryCondition<ModelType>::applyBC(const FunctorType & func, const std::string & group_name) { try { const ElementGroup & element_group = model->getMesh().getElementGroup(group_name); applyBC(func, element_group); } catch (akantu::debug::Exception e) { AKANTU_EXCEPTION("Error applying a boundary condition onto \"" << group_name << "\"! [" << e.what() << "]"); } } /* -------------------------------------------------------------------------- */ template <typename ModelType> template <typename FunctorType> inline void BoundaryCondition<ModelType>::applyBC(const FunctorType & func, const ElementGroup & element_group) { #if !defined(AKANTU_NDEBUG) if (element_group.getDimension() != model->getSpatialDimension() - 1) AKANTU_DEBUG_WARNING("The group " << element_group.getName() << " does not contain only boundaries elements"); #endif TemplateFunctionWrapper<FunctorType>::applyBC(func, element_group, *this); } #endif /* __AKANTU_BOUNDARY_CONDITION_TMPL_HH__ */ } // namespace akantu diff --git a/src/model/common/neighborhood_base.cc b/src/model/common/neighborhood_base.cc index 1fbf3f5a4..aada85368 100644 --- a/src/model/common/neighborhood_base.cc +++ b/src/model/common/neighborhood_base.cc @@ -1,295 +1,295 @@ /** * @file neighborhood_base.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sat Sep 26 2015 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of generic neighborhood base * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" #include "grid_synchronizer.hh" #include "mesh_accessor.hh" #include "model.hh" /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NeighborhoodBase::NeighborhoodBase(Model & model, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), model(model), neighborhood_radius(0.), spatial_grid(nullptr), is_creating_grid(false), grid_synchronizer(nullptr), quad_coordinates(quad_coordinates), spatial_dimension(this->model.getMesh().getSpatialDimension()) { AKANTU_DEBUG_IN(); this->registerDataAccessor(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NeighborhoodBase::~NeighborhoodBase() = default; /* -------------------------------------------------------------------------- */ // void NeighborhoodBase::createSynchronizerRegistry( // DataAccessor<Element> * data_accessor) { // this->synch_registry = new SynchronizerRegistry(*data_accessor); // } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::initNeighborhood() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Creating the grid"); this->createGrid(); AKANTU_DEBUG_OUT(); } /* ------------------------------------------------------------------------- */ void NeighborhoodBase::createGrid() { AKANTU_DEBUG_IN(); const Real safety_factor = 1.2; // for the cell grid spacing Mesh & mesh = this->model.getMesh(); const auto & lower_bounds = mesh.getLocalLowerBounds(); const auto & upper_bounds = mesh.getLocalUpperBounds(); Vector<Real> center = 0.5 * (upper_bounds + lower_bounds); Vector<Real> spacing(spatial_dimension, this->neighborhood_radius * safety_factor); spatial_grid = std::make_unique<SpatialGrid<IntegrationPoint>>( spatial_dimension, spacing, center); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::updatePairList() { AKANTU_DEBUG_IN(); //// loop over all quads -> all cells for (auto && cell_id : *spatial_grid) { AKANTU_DEBUG_INFO("Looping on next cell"); for (auto && q1 : spatial_grid->getCell(cell_id)) { if (q1.ghost_type == _ghost) break; auto coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(spatial_dimension); auto q1_coords = Vector<Real>(coords_type_1_it[q1.global_num]); AKANTU_DEBUG_INFO("Current quadrature point in this cell: " << q1); auto cell_id = spatial_grid->getCellID(q1_coords); /// loop over all the neighboring cells of the current quad for (auto && neighbor_cell : cell_id.neighbors()) { // loop over the quadrature point in the current neighboring cell for (auto && q2 : spatial_grid->getCell(neighbor_cell)) { auto coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(spatial_dimension); auto q2_coords = Vector<Real>(coords_type_2_it[q2.global_num]); Real distance = q1_coords.distance(q2_coords); if (distance <= this->neighborhood_radius + Math::getTolerance() && (q2.ghost_type == _ghost || (q2.ghost_type == _not_ghost && q1.global_num <= q2.global_num))) { // storing only half lists pair_list[q2.ghost_type].push_back(std::make_pair(q1, q2)); } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::savePairs(const std::string & filename) const { std::stringstream sstr; const Communicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; std::ofstream pout; pout.open(sstr.str().c_str()); for (auto && ghost_type : ghost_types) { for (const auto & pair : pair_list[ghost_type]) { const auto & q1 = pair.first; const auto & q2 = pair.second; pout << q1 << " " << q2 << " " << std::endl; } } pout.close(); if (comm.getNbProc() != 1) return; Mesh mesh_out(spatial_dimension); MeshAccessor mesh_accessor(mesh_out); auto & connectivity = mesh_accessor.getConnectivity(_segment_2); auto & tag = mesh_accessor.getData<UInt>("tag_1", _segment_2); auto & nodes = mesh_accessor.getNodes(); std::map<IntegrationPoint, UInt> quad_to_nodes; UInt node = 0; IntegrationPoint q1, q2; bool inserted; for (auto && ghost_type : ghost_types) { for (const auto & pair : pair_list[ghost_type]) { std::tie(q1, q2) = pair; auto add_node = [&](auto && q) { std::tie(std::ignore, inserted) = quad_to_nodes.insert(std::make_pair(q, node)); if (not inserted) return; auto coords_it = this->quad_coordinates(q.type, q.ghost_type) .begin(spatial_dimension); auto && coords = Vector<Real>(coords_it[q.global_num]); nodes.push_back(coords); ++node; }; add_node(q1); add_node(q2); } } for (auto && ghost_type : ghost_types) { for (const auto & pair : pair_list[ghost_type]) { std::tie(q1, q2) = pair; UInt node1 = quad_to_nodes[q1]; UInt node2 = quad_to_nodes[q2]; connectivity.push_back(Vector<UInt>{node1, node2}); tag.push_back(node1 + 1); if (node1 != node2) { connectivity.push_back(Vector<UInt>{node2, node1}); tag.push_back(node2 + 1); } } } mesh_out.write(filename + ".msh"); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::saveNeighborCoords(const std::string & filename) const { // this function is not optimized and only used for tests on small meshes // @todo maybe optimize this function for better performance? IntegrationPoint q2; std::stringstream sstr; const Communicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; std::ofstream pout; pout.open(sstr.str().c_str()); /// loop over all the quads and write the position of their neighbors for (auto && cell_id : *spatial_grid) { for (auto && q1 : spatial_grid->getCell(cell_id)) { auto coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(spatial_dimension); auto && q1_coords = Vector<Real>(coords_type_1_it[q1.global_num]); pout << "#neighbors for quad " << q1.global_num << std::endl; pout << q1_coords << std::endl; for (auto && ghost_type2 : ghost_types) { for (auto && pair : pair_list[ghost_type2]) { if (q1 == pair.first && pair.second != q1) { q2 = pair.second; } else if (q1 == pair.second && pair.first != q1) { q2 = pair.first; } else { continue; } auto coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(spatial_dimension); auto && q2_coords = Vector<Real>(coords_type_2_it[q2.global_num]); pout << q2_coords << std::endl; } } } } } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::onElementsRemoved( const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = 0; // Change the pairs in new global numbering for (auto ghost_type2 : ghost_types) { for (auto && pair : pair_list[ghost_type2]) { auto cleanPoint = [&](auto && q) { if (new_numbering.exists(q.type, q.ghost_type)) { UInt q_new_el = new_numbering(q.type, q.ghost_type)(q.element); AKANTU_DEBUG_ASSERT(q_new_el != UInt(-1), "A local quadrature_point " "as been removed instead of " "just being renumbered"); q.element = q_new_el; nb_quad = fem.getNbIntegrationPoints(q.type, q.ghost_type); q.global_num = nb_quad * q.element + q.num_point; } }; cleanPoint(pair.first); cleanPoint(pair.second); } } this->grid_synchronizer->onElementsRemoved(element_list, new_numbering, event); AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/common/neighborhood_base.hh b/src/model/common/neighborhood_base.hh index e0c51f496..a9dabe632 100644 --- a/src/model/common/neighborhood_base.hh +++ b/src/model/common/neighborhood_base.hh @@ -1,151 +1,151 @@ /** * @file neighborhood_base.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sat Sep 26 2015 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Generic neighborhood of quadrature points * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NEIGHBORHOOD_BASE_HH__ #define __AKANTU_NEIGHBORHOOD_BASE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "data_accessor.hh" #include "integration_point.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Model; template <class T> class SpatialGrid; class GridSynchronizer; class RemovedElementsEvent; } // namespace akantu namespace akantu { class NeighborhoodBase : protected Memory, public DataAccessor<Element>, public SynchronizerRegistry { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NeighborhoodBase(Model & model, const ElementTypeMapArray<Real> & quad_coordinates, const ID & id = "neighborhood", const MemoryID & memory_id = 0); ~NeighborhoodBase() override; using PairList = std::vector<std::pair<IntegrationPoint, IntegrationPoint>>; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// intialize the neighborhood virtual void initNeighborhood(); // /// create a synchronizer registry // void createSynchronizerRegistry(DataAccessor * data_accessor); /// initialize the material computed parameter inline void insertIntegrationPoint(const IntegrationPoint & quad, const Vector<Real> & coords); /// create the pairs of quadrature points void updatePairList(); /// save the pairs of quadrature points in a file void savePairs(const std::string & filename) const; /// save the coordinates of all neighbors of a quad void saveNeighborCoords(const std::string & filename) const; /// create grid synchronizer and exchange ghost cells virtual void createGridSynchronizer() = 0; virtual void synchronize(DataAccessor<Element> & data_accessor, const SynchronizationTag & tag) = 0; /// inherited function from MeshEventHandler virtual void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event); protected: /// create the grid void createGrid(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); AKANTU_GET_MACRO(Model, model, const Model &); /// return the object handling synchronizers AKANTU_GET_MACRO(PairLists, pair_list, const PairList *); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the model to which the neighborhood belongs Model & model; /// Radius of impact: to determine if two quadrature points influence each /// other Real neighborhood_radius; /** * the pairs of quadrature points * 0: not ghost to not ghost * 1: not ghost to ghost */ PairList pair_list[2]; /// the regular grid to construct/update the pair lists std::unique_ptr<SpatialGrid<IntegrationPoint>> spatial_grid; bool is_creating_grid; /// the grid synchronizer for parallel computations std::unique_ptr<GridSynchronizer> grid_synchronizer; /// the quadrature point positions const ElementTypeMapArray<Real> & quad_coordinates; /// the spatial dimension of the problem const UInt spatial_dimension; }; } // namespace akantu #include "neighborhood_base_inline_impl.cc" #endif /* __AKANTU_NEIGHBORHOOD_BASE_HH__ */ diff --git a/src/model/common/neighborhood_base_inline_impl.cc b/src/model/common/neighborhood_base_inline_impl.cc index ebed56d3f..70de7429f 100644 --- a/src/model/common/neighborhood_base_inline_impl.cc +++ b/src/model/common/neighborhood_base_inline_impl.cc @@ -1,50 +1,50 @@ /** * @file neighborhood_base_inline_impl.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Inline implementation of neighborhood base functions * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_grid_dynamic.hh" #include "neighborhood_base.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NEIGHBORHOOD_BASE_INLINE_IMPL_CC__ #define __AKANTU_NEIGHBORHOOD_BASE_INLINE_IMPL_CC__ namespace akantu { inline void NeighborhoodBase::insertIntegrationPoint(const IntegrationPoint & quad, const Vector<Real> & coords) { this->spatial_grid->insert(quad, coords); } } // namespace akantu #endif /* __AKANTU_NEIGHBORHOOD_BASE_INLINE_IMPL_CC__ */ diff --git a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc index 6468159a4..bc55e366a 100644 --- a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc +++ b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc @@ -1,311 +1,311 @@ /** * @file neighborhood_max_criterion.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Thu Oct 15 2015 - * @date last modification: Tue Nov 24 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of class NeighborhoodMaxCriterion * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "neighborhood_max_criterion.hh" #include "grid_synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NeighborhoodMaxCriterion::NeighborhoodMaxCriterion( Model & model, const ElementTypeMapReal & quad_coordinates, const ID & criterion_id, const ID & id, const MemoryID & memory_id) : NeighborhoodBase(model, quad_coordinates, id, memory_id), Parsable(ParserType::_non_local, id), is_highest("is_highest", id, memory_id), criterion(criterion_id, id, memory_id) { AKANTU_DEBUG_IN(); this->registerParam("radius", neighborhood_radius, 100., _pat_parsable | _pat_readable, "Non local radius"); Mesh & mesh = this->model.getMesh(); /// allocate the element type map arrays for _not_ghosts: One entry per quad GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { UInt new_size = this->quad_coordinates(*it, ghost_type).size(); this->is_highest.alloc(new_size, 1, *it, ghost_type, true); this->criterion.alloc(new_size, 1, *it, ghost_type, true); } /// criterion needs allocation also for ghost ghost_type = _ghost; it = mesh.firstType(spatial_dimension, ghost_type); last_type = mesh.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { UInt new_size = this->quad_coordinates(*it, ghost_type).size(); this->criterion.alloc(new_size, 1, *it, ghost_type, true); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NeighborhoodMaxCriterion::~NeighborhoodMaxCriterion() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::initNeighborhood() { AKANTU_DEBUG_IN(); /// parse the input parameter const Parser & parser = getStaticParser(); const ParserSection & section_neighborhood = *(parser.getSubSections(ParserType::_neighborhood).first); this->parseSection(section_neighborhood); AKANTU_DEBUG_INFO("Creating the grid"); this->createGrid(); /// insert the non-ghost quads into the grid this->insertAllQuads(_not_ghost); /// store the number of current ghost elements for each type in the mesh ElementTypeMap<UInt> nb_ghost_protected; Mesh & mesh = this->model.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); for (; it != last_type; ++it) nb_ghost_protected(mesh.getNbElement(*it, _ghost), *it, _ghost); /// create the grid synchronizer this->createGridSynchronizer(); /// insert the ghost quads into the grid this->insertAllQuads(_ghost); /// create the pair lists this->updatePairList(); /// remove the unneccessary ghosts this->cleanupExtraGhostElements(nb_ghost_protected); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::createGridSynchronizer() { this->is_creating_grid = true; std::set<SynchronizationTag> tags; tags.insert(_gst_nh_criterion); std::stringstream sstr; sstr << getID() << ":grid_synchronizer"; this->grid_synchronizer = std::make_unique<GridSynchronizer>( this->model.getMesh(), *spatial_grid, *this, tags, sstr.str(), 0, false); this->is_creating_grid = false; } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::insertAllQuads(const GhostType & ghost_type) { IntegrationPoint q; q.ghost_type = ghost_type; Mesh & mesh = this->model.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); UInt nb_quad = this->model.getFEEngine().getNbIntegrationPoints(*it, ghost_type); const Array<Real> & quads = this->quad_coordinates(*it, ghost_type); q.type = *it; auto quad = quads.begin(spatial_dimension); for (UInt e = 0; e < nb_element; ++e) { q.element = e; for (UInt nq = 0; nq < nb_quad; ++nq) { q.num_point = nq; q.global_num = q.element * nb_quad + nq; spatial_grid->insert(q, *quad); ++quad; } } } } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::findMaxQuads( std::vector<IntegrationPoint> & max_quads) { AKANTU_DEBUG_IN(); /// clear the element type maps this->is_highest.clear(); this->criterion.clear(); /// update the values of the criterion this->model.updateDataForNonLocalCriterion(criterion); /// start the exchange the value of the criterion on the ghost elements this->model.asynchronousSynchronize(_gst_nh_criterion); /// compare to not-ghost neighbors checkNeighbors(_not_ghost); /// finish the exchange this->model.waitEndSynchronize(_gst_nh_criterion); /// compare to ghost neighbors checkNeighbors(_ghost); /// extract the quads with highest criterion in their neighborhood IntegrationPoint quad; quad.ghost_type = _not_ghost; Mesh & mesh = this->model.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost); for (; it != last_type; ++it) { quad.type = *it; Array<bool>::const_scalar_iterator is_highest_it = is_highest(*it, _not_ghost).begin(); Array<bool>::const_scalar_iterator is_highest_end = is_highest(*it, _not_ghost).end(); UInt nb_quadrature_points = this->model.getFEEngine().getNbIntegrationPoints(*it, _not_ghost); UInt q = 0; /// loop over is_highest for the current element type for (; is_highest_it != is_highest_end; ++is_highest_it, ++q) { if (*is_highest_it) { /// gauss point has the highest stress in his neighbourhood quad.element = q / nb_quadrature_points; quad.global_num = q; quad.num_point = q % nb_quadrature_points; max_quads.push_back(quad); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::checkNeighbors(const GhostType & ghost_type2) { AKANTU_DEBUG_IN(); PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); // Compute the weights for (; first_pair != last_pair; ++first_pair) { const IntegrationPoint & lq1 = first_pair->first; const IntegrationPoint & lq2 = first_pair->second; Array<bool> & has_highest_eq_stress_1 = is_highest(lq1.type, lq1.ghost_type); const Array<Real> & criterion_1 = this->criterion(lq1.type, lq1.ghost_type); const Array<Real> & criterion_2 = this->criterion(lq2.type, lq2.ghost_type); if (criterion_1(lq1.global_num) < criterion_2(lq2.global_num)) has_highest_eq_stress_1(lq1.global_num) = false; else if (ghost_type2 != _ghost) { Array<bool> & has_highest_eq_stress_2 = is_highest(lq2.type, lq2.ghost_type); has_highest_eq_stress_2(lq2.global_num) = false; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::cleanupExtraGhostElements( const ElementTypeMap<UInt> & nb_ghost_protected) { Mesh & mesh = this->model.getMesh(); /// create remove elements event RemovedElementsEvent remove_elem(mesh); /// create set of ghosts to keep std::set<Element> relevant_ghost_elements; PairList::const_iterator first_pair = pair_list[_ghost].begin(); PairList::const_iterator last_pair = pair_list[_ghost].end(); for (; first_pair != last_pair; ++first_pair) { const IntegrationPoint & q2 = first_pair->second; relevant_ghost_elements.insert(q2); } Array<Element> ghosts_to_erase(0); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); Element element; element.ghost_type = _ghost; auto end = relevant_ghost_elements.end(); for (; it != last_type; ++it) { element.type = *it; UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); UInt nb_ghost_elem_protected = 0; try { nb_ghost_elem_protected = nb_ghost_protected(*it, _ghost); } catch (...) { } if (!remove_elem.getNewNumbering().exists(*it, _ghost)) remove_elem.getNewNumbering().alloc(nb_ghost_elem, 1, *it, _ghost); else remove_elem.getNewNumbering(*it, _ghost).resize(nb_ghost_elem); Array<UInt> & new_numbering = remove_elem.getNewNumbering(*it, _ghost); for (UInt g = 0; g < nb_ghost_elem; ++g) { element.element = g; if (element.element >= nb_ghost_elem_protected && relevant_ghost_elements.find(element) == end) { ghosts_to_erase.push_back(element); new_numbering(element.element) = UInt(-1); } } /// renumber remaining ghosts UInt ng = 0; for (UInt g = 0; g < nb_ghost_elem; ++g) { if (new_numbering(g) != UInt(-1)) { new_numbering(g) = ng; ++ng; } } } mesh.sendEvent(remove_elem); this->onElementsRemoved(ghosts_to_erase, remove_elem.getNewNumbering(), remove_elem); } } // namespace akantu diff --git a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh index 67b7f51c9..8ff079040 100644 --- a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh +++ b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh @@ -1,117 +1,117 @@ /** * @file neighborhood_max_criterion.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Sat Sep 26 2015 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Neighborhood to find a maximum value in a neighborhood * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NEIGHBORHOOD_MAX_CRITERION_BASE_HH__ #define __AKANTU_NEIGHBORHOOD_MAX_CRITERION_BASE_HH__ /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class NeighborhoodMaxCriterion : public NeighborhoodBase, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NeighborhoodMaxCriterion(Model & model, const ElementTypeMapReal & quad_coordinates, const ID & criterion_id, const ID & id = "neighborhood_max_criterion", const MemoryID & memory_id = 0); ~NeighborhoodMaxCriterion() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the neighborhood void initNeighborhood() override; /// create grid synchronizer and exchange ghost cells void createGridSynchronizer() override; /// find the quads which have the maximum criterion in their neighborhood void findMaxQuads(std::vector<IntegrationPoint> & max_quads); protected: /// remove unneccessary ghost elements void cleanupExtraGhostElements(const ElementTypeMap<UInt> & nb_ghost_protected); /// insert the quadrature points in the grid void insertAllQuads(const GhostType & ghost_type); /// compare criterion with neighbors void checkNeighbors(const GhostType & ghost_type); /* -------------------------------------------------------------------------- */ /* DataAccessor inherited members */ /* -------------------------------------------------------------------------- */ public: virtual inline UInt getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const; virtual inline void packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const; virtual inline void unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag); /* -------------------------------------------------------------------------- */ /* Accessors */ /* -------------------------------------------------------------------------- */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// a boolean to store the information if a quad has the max /// criterion in the neighborhood ElementTypeMapArray<bool> is_highest; /// an element type map to store the flattened internal of the criterion ElementTypeMapReal criterion; }; } // akantu #include "neighborhood_max_criterion_inline_impl.cc" #endif /* __AKANTU_NEIGHBORHOOD_MAX_CRITERION_BASE_HH__ */ diff --git a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion_inline_impl.cc b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion_inline_impl.cc index bb2d331cb..a74051e21 100644 --- a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion_inline_impl.cc +++ b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion_inline_impl.cc @@ -1,81 +1,82 @@ /** * @file neighborhood_max_criterion_inline_impl.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sat Sep 26 2015 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of inline functions for class NeighborhoodMaxCriterion * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "model.hh" #include "neighborhood_max_criterion.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NEIGHBORHOOD_MAX_CRITERION_INLINE_IMPL_CC__ #define __AKANTU_NEIGHBORHOOD_MAX_CRITERION_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt NeighborhoodMaxCriterion::getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const { UInt nb_quadrature_points = this->model.getNbIntegrationPoints(elements); UInt size = 0; if (tag == _gst_nh_criterion) { size += sizeof(Real) * nb_quadrature_points; } return size; } /* -------------------------------------------------------------------------- */ inline void NeighborhoodMaxCriterion::packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const { if (tag == _gst_nh_criterion) { this->packElementalDataHelper(criterion, buffer, elements, true, this->model.getFEEngine()); } } /* -------------------------------------------------------------------------- */ inline void NeighborhoodMaxCriterion::unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) { if (tag == _gst_nh_criterion) { this->unpackElementalDataHelper(criterion, buffer, elements, true, this->model.getFEEngine()); } } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_NEIGHBORHOOD_MAX_CRITERION_INLINE_IMPL_CC__ */ diff --git a/src/model/common/non_local_toolbox/base_weight_function.hh b/src/model/common/non_local_toolbox/base_weight_function.hh index 202b20073..94808505a 100644 --- a/src/model/common/non_local_toolbox/base_weight_function.hh +++ b/src/model/common/non_local_toolbox/base_weight_function.hh @@ -1,169 +1,169 @@ /** * @file base_weight_function.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Mon Aug 24 2015 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Fri Dec 08 2017 * * @brief Base weight function for non local materials * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "model.hh" #include "non_local_manager.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BASE_WEIGHT_FUNCTION_HH__ #define __AKANTU_BASE_WEIGHT_FUNCTION_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Normal weight function */ /* -------------------------------------------------------------------------- */ class BaseWeightFunction : public Parsable, public DataAccessor<Element> { public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ BaseWeightFunction(NonLocalManager & manager, const std::string & type = "base") : Parsable(ParserType::_weight_function, "weight_function:" + type), manager(manager), type(type), spatial_dimension(manager.getModel().getMesh().getSpatialDimension()) { this->registerParam("update_rate", update_rate, UInt(1), _pat_parsmod, "Update frequency"); } ~BaseWeightFunction() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ /// initialize the weight function virtual inline void init(); /// update the internal parameters virtual void updateInternals(){}; /* ------------------------------------------------------------------------ */ /// set the non-local radius inline void setRadius(Real radius); /* ------------------------------------------------------------------------ */ /// compute the weight for a given distance between two quadrature points inline Real operator()(Real r, const IntegrationPoint & q1, const IntegrationPoint & q2); /// print function void printself(std::ostream & stream, int indent = 0) const override { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "WeightFunction " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /* Accessors */ /* -------------------------------------------------------------------------- */ public: /// get the radius Real getRadius() { return R; } /// get the update rate UInt getUpdateRate() { return update_rate; } public: /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ UInt getNbData(const Array<Element> &, const SynchronizationTag &) const override { return 0; } inline void packData(CommunicationBuffer &, const Array<Element> &, const SynchronizationTag &) const override {} inline void unpackData(CommunicationBuffer &, const Array<Element> &, const SynchronizationTag &) override {} /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Type, type, const ID &); protected: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ /// reference to the non-local manager NonLocalManager & manager; /// the non-local radius Real R; /// the non-local radius squared Real R2; /// the update rate UInt update_rate; /// name of the type of weight function const std::string type; /// the spatial dimension UInt spatial_dimension; }; inline std::ostream & operator<<(std::ostream & stream, const BaseWeightFunction & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "base_weight_function_inline_impl.cc" /* -------------------------------------------------------------------------- */ /* Include all other weight function types */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_DAMAGE_NON_LOCAL) #include "damaged_weight_function.hh" #include "remove_damaged_weight_function.hh" #include "remove_damaged_with_damage_rate_weight_function.hh" #include "stress_based_weight_function.hh" #endif /* -------------------------------------------------------------------------- */ #endif /* __AKANTU_BASE_WEIGHT_FUNCTION_HH__ */ diff --git a/src/model/common/non_local_toolbox/base_weight_function_inline_impl.cc b/src/model/common/non_local_toolbox/base_weight_function_inline_impl.cc index 0c185e079..d80ccb2cf 100644 --- a/src/model/common/non_local_toolbox/base_weight_function_inline_impl.cc +++ b/src/model/common/non_local_toolbox/base_weight_function_inline_impl.cc @@ -1,70 +1,71 @@ /** * @file base_weight_function_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * - * @date creation: Thu Feb 21 2013 - * @date last modification: Thu Oct 15 2015 + * @date creation: Wed Sep 01 2010 + * @date last modification: Wed Sep 27 2017 * * @brief Implementation of inline function of base weight function * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "base_weight_function.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BASE_WEIGHT_FUNCTION_INLINE_IMPL_CC__ #define __AKANTU_BASE_WEIGHT_FUNCTION_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline void BaseWeightFunction::init() { /// compute R^2 for a given non-local radius this->R2 = this->R * this->R; } /* -------------------------------------------------------------------------- */ inline void BaseWeightFunction::setRadius(Real radius) { /// set the non-local radius and update R^2 accordingly this->R = radius; this->R2 = this->R * this->R; } /* -------------------------------------------------------------------------- */ inline Real BaseWeightFunction::operator()(Real r, const IntegrationPoint &, const IntegrationPoint &) { /// initialize the weight Real w = 0; /// compute weight for given r if (r <= this->R) { Real alpha = (1. - r * r / this->R2); w = alpha * alpha; // *weight = 1 - sqrt(r / radius); } return w; } } // akantu #endif /* __AKANTU_BASE_WEIGHT_FUNCTION_INLINE_IMPL_CC__ */ diff --git a/src/model/common/non_local_toolbox/non_local_manager.cc b/src/model/common/non_local_toolbox/non_local_manager.cc index 386c3ee82..7fb9868df 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.cc +++ b/src/model/common/non_local_toolbox/non_local_manager.cc @@ -1,639 +1,638 @@ /** * @file non_local_manager.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Apr 13 2012 - * @date last modification: Wed Dec 16 2015 + * @date last modification: Tue Jan 16 2018 * * @brief Implementation of non-local manager * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_local_manager.hh" #include "grid_synchronizer.hh" #include "model.hh" #include "non_local_neighborhood.hh" /* -------------------------------------------------------------------------- */ #include <numeric> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLocalManager::NonLocalManager(Model & model, NonLocalManagerCallback & callback, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), Parsable(ParserType::_neighborhoods, id), spatial_dimension(model.getMesh().getSpatialDimension()), model(model), integration_points_positions("integration_points_positions", id, memory_id), volumes("volumes", id, memory_id), compute_stress_calls(0), dummy_registry(nullptr), dummy_grid(nullptr) { /// parse the neighborhood information from the input file const Parser & parser = getStaticParser(); /// iterate over all the non-local sections and store them in a map std::pair<Parser::const_section_iterator, Parser::const_section_iterator> weight_sect = parser.getSubSections(ParserType::_non_local); Parser::const_section_iterator it = weight_sect.first; for (; it != weight_sect.second; ++it) { const ParserSection & section = *it; ID name = section.getName(); this->weight_function_types[name] = section; } this->callback = &callback; } /* -------------------------------------------------------------------------- */ NonLocalManager::~NonLocalManager() = default; /* -------------------------------------------------------------------------- */ void NonLocalManager::initialize() { volumes.initialize(this->model.getFEEngine(), _spatial_dimension = spatial_dimension); AKANTU_DEBUG_ASSERT(this->callback, "A callback should be registered prior to this call"); this->callback->insertIntegrationPointsInNeighborhoods(_not_ghost); auto & mesh = this->model.getMesh(); mesh.registerEventHandler(*this, _ehp_non_local_manager); /// store the number of current ghost elements for each type in the mesh // ElementTypeMap<UInt> nb_ghost_protected; // for (auto type : mesh.elementTypes(spatial_dimension, _ghost)) // nb_ghost_protected(mesh.getNbElement(type, _ghost), type, _ghost); /// exchange the missing ghosts for the non-local neighborhoods this->createNeighborhoodSynchronizers(); /// insert the ghost quadrature points of the non-local materials into the /// non-local neighborhoods this->callback->insertIntegrationPointsInNeighborhoods(_ghost); FEEngine & fee = this->model.getFEEngine(); this->updatePairLists(); /// cleanup the unneccessary ghost elements this->cleanupExtraGhostElements(); // nb_ghost_protected); this->callback->initializeNonLocal(); this->setJacobians(fee, _ek_regular); this->initNonLocalVariables(); this->computeWeights(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::setJacobians(const FEEngine & fe_engine, const ElementKind & kind) { Mesh & mesh = this->model.getMesh(); for (auto ghost_type : ghost_types) { for (auto type : mesh.elementTypes(spatial_dimension, ghost_type, kind)) { jacobians(type, ghost_type) = &fe_engine.getIntegratorInterface().getJacobians(type, ghost_type); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhood(const ID & weight_func, const ID & neighborhood_id) { AKANTU_DEBUG_IN(); auto weight_func_it = this->weight_function_types.find(weight_func); AKANTU_DEBUG_ASSERT(weight_func_it != weight_function_types.end(), "No info found in the input file for the weight_function " << weight_func << " in the neighborhood " << neighborhood_id); const ParserSection & section = weight_func_it->second; const ID weight_func_type = section.getOption(); /// create new neighborhood for given ID std::stringstream sstr; sstr << id << ":neighborhood:" << neighborhood_id; if (weight_func_type == "base_wf") neighborhoods[neighborhood_id] = std::make_unique<NonLocalNeighborhood<BaseWeightFunction>>( *this, this->integration_points_positions, sstr.str()); #if defined(AKANTU_DAMAGE_NON_LOCAL) else if (weight_func_type == "remove_wf") neighborhoods[neighborhood_id] = std::make_unique<NonLocalNeighborhood<RemoveDamagedWeightFunction>>( *this, this->integration_points_positions, sstr.str()); else if (weight_func_type == "stress_wf") neighborhoods[neighborhood_id] = std::make_unique<NonLocalNeighborhood<StressBasedWeightFunction>>( *this, this->integration_points_positions, sstr.str()); else if (weight_func_type == "damage_wf") neighborhoods[neighborhood_id] = std::make_unique<NonLocalNeighborhood<DamagedWeightFunction>>( *this, this->integration_points_positions, sstr.str()); #endif else AKANTU_EXCEPTION("error in weight function type provided in material file"); neighborhoods[neighborhood_id]->parseSection(section); neighborhoods[neighborhood_id]->initNeighborhood(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhoodSynchronizers() { /// exchange all the neighborhood IDs, so that every proc knows how many /// neighborhoods exist globally /// First: Compute locally the maximum ID size UInt max_id_size = 0; UInt current_size = 0; NeighborhoodMap::const_iterator it; for (it = neighborhoods.begin(); it != neighborhoods.end(); ++it) { current_size = it->first.size(); if (current_size > max_id_size) max_id_size = current_size; } /// get the global maximum ID size on each proc const Communicator & static_communicator = model.getMesh().getCommunicator(); static_communicator.allReduce(max_id_size, SynchronizerOperation::_max); /// get the rank for this proc and the total nb proc UInt prank = static_communicator.whoAmI(); UInt psize = static_communicator.getNbProc(); /// exchange the number of neighborhoods on each proc Array<Int> nb_neighborhoods_per_proc(psize); nb_neighborhoods_per_proc(prank) = neighborhoods.size(); static_communicator.allGather(nb_neighborhoods_per_proc); /// compute the total number of neighborhoods UInt nb_neighborhoods_global = std::accumulate( nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.end(), 0); /// allocate an array of chars to store the names of all neighborhoods Array<char> buffer(nb_neighborhoods_global, max_id_size); /// starting index on this proc UInt starting_index = std::accumulate(nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.begin() + prank, 0); it = neighborhoods.begin(); /// store the names of local neighborhoods in the buffer for (UInt i = 0; i < neighborhoods.size(); ++i, ++it) { UInt c = 0; for (; c < it->first.size(); ++c) buffer(i + starting_index, c) = it->first[c]; for (; c < max_id_size; ++c) buffer(i + starting_index, c) = char(0); } /// store the nb of data to send in the all gather Array<Int> buffer_size(nb_neighborhoods_per_proc); buffer_size *= max_id_size; /// exchange the names of all the neighborhoods with all procs static_communicator.allGatherV(buffer, buffer_size); for (UInt i = 0; i < nb_neighborhoods_global; ++i) { std::stringstream neighborhood_id; for (UInt c = 0; c < max_id_size; ++c) { if (buffer(i, c) == char(0)) break; neighborhood_id << buffer(i, c); } global_neighborhoods.insert(neighborhood_id.str()); } /// this proc does not know all the neighborhoods -> create dummy /// grid so that this proc can participate in the all gather for /// detecting the overlap of neighborhoods this proc doesn't know Vector<Real> grid_center(this->spatial_dimension, std::numeric_limits<Real>::max()); Vector<Real> spacing(this->spatial_dimension, 0.); dummy_grid = std::make_unique<SpatialGrid<IntegrationPoint>>( this->spatial_dimension, spacing, grid_center); for (auto & neighborhood_id : global_neighborhoods) { it = neighborhoods.find(neighborhood_id); if (it != neighborhoods.end()) { it->second->createGridSynchronizer(); } else { dummy_synchronizers[neighborhood_id] = std::make_unique<GridSynchronizer>( this->model.getMesh(), *dummy_grid, std::string(this->id + ":" + neighborhood_id + ":grid_synchronizer"), this->memory_id, false); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::synchronize(DataAccessor<Element> & data_accessor, const SynchronizationTag & tag) { for (auto & neighborhood_id : global_neighborhoods) { auto it = neighborhoods.find(neighborhood_id); if (it != neighborhoods.end()) { it->second->synchronize(data_accessor, tag); } else { auto synchronizer_it = dummy_synchronizers.find(neighborhood_id); if (synchronizer_it == dummy_synchronizers.end()) continue; synchronizer_it->second->synchronizeOnce(data_accessor, tag); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::averageInternals(const GhostType & ghost_type) { /// update the weights of the weight function if (ghost_type == _not_ghost) this->computeWeights(); /// loop over all neighborhoods and compute the non-local variables for (auto & neighborhood : neighborhoods) { /// loop over all the non-local variables of the given neighborhood for (auto & non_local_variable : non_local_variables) { NonLocalVariable & non_local_var = *non_local_variable.second; neighborhood.second->weightedAverageOnNeighbours( non_local_var.local, non_local_var.non_local, non_local_var.nb_component, ghost_type); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::computeWeights() { AKANTU_DEBUG_IN(); this->updateWeightFunctionInternals(); this->volumes.clear(); for (const auto & global_neighborhood : global_neighborhoods) { auto it = neighborhoods.find(global_neighborhood); if (it != neighborhoods.end()) it->second->updateWeights(); else { dummy_synchronizers[global_neighborhood]->synchronize(dummy_accessor, _gst_mnl_weight); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::updatePairLists() { AKANTU_DEBUG_IN(); integration_points_positions.initialize( this->model.getFEEngine(), _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension); /// compute the position of the quadrature points this->model.getFEEngine().computeIntegrationPointsCoordinates( integration_points_positions); for (auto & pair : neighborhoods) pair.second->updatePairList(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::registerNonLocalVariable(const ID & variable_name, const ID & nl_variable_name, UInt nb_component) { AKANTU_DEBUG_IN(); auto non_local_variable_it = non_local_variables.find(variable_name); if (non_local_variable_it == non_local_variables.end()) non_local_variables[nl_variable_name] = std::make_unique<NonLocalVariable>( variable_name, nl_variable_name, this->id, nb_component); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementTypeMapReal & NonLocalManager::registerWeightFunctionInternal(const ID & field_name) { AKANTU_DEBUG_IN(); auto it = this->weight_function_internals.find(field_name); if (it == weight_function_internals.end()) { weight_function_internals[field_name] = std::make_unique<ElementTypeMapReal>(field_name, this->id, this->memory_id); } AKANTU_DEBUG_OUT(); return *(weight_function_internals[field_name]); } /* -------------------------------------------------------------------------- */ void NonLocalManager::updateWeightFunctionInternals() { for (auto & pair : this->weight_function_internals) { auto & internals = *pair.second; internals.clear(); for (auto ghost_type : ghost_types) this->callback->updateLocalInternal(internals, ghost_type, _ek_regular); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::initNonLocalVariables() { /// loop over all the non-local variables for (auto & pair : non_local_variables) { auto & variable = *pair.second; variable.non_local.initialize(this->model.getFEEngine(), _nb_component = variable.nb_component, _spatial_dimension = spatial_dimension); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::computeAllNonLocalStresses() { /// update the flattened version of the internals for (auto & pair : non_local_variables) { auto & variable = *pair.second; variable.local.clear(); variable.non_local.clear(); for (auto ghost_type : ghost_types) { this->callback->updateLocalInternal(variable.local, ghost_type, _ek_regular); } } this->volumes.clear(); for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; neighborhood.asynchronousSynchronize(_gst_mnl_for_average); } this->averageInternals(_not_ghost); AKANTU_DEBUG_INFO("Wait distant non local stresses"); for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; neighborhood.waitEndSynchronize(_gst_mnl_for_average); } this->averageInternals(_ghost); /// copy the results in the materials for (auto & pair : non_local_variables) { auto & variable = *pair.second; for (auto ghost_type : ghost_types) { this->callback->updateNonLocalInternal(variable.non_local, ghost_type, _ek_regular); } } this->callback->computeNonLocalStresses(_not_ghost); ++this->compute_stress_calls; } /* -------------------------------------------------------------------------- */ void NonLocalManager::cleanupExtraGhostElements() { // ElementTypeMap<UInt> & nb_ghost_protected) { using ElementSet = std::set<Element>; ElementSet relevant_ghost_elements; /// loop over all the neighborhoods and get their protected ghosts for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; ElementSet to_keep_per_neighborhood; neighborhood.cleanupExtraGhostElements(to_keep_per_neighborhood); for (auto & element : to_keep_per_neighborhood) relevant_ghost_elements.insert(element); } // /// remove all unneccessary ghosts from the mesh // /// Create list of element to remove and new numbering for element to keep // Mesh & mesh = this->model.getMesh(); // ElementSet ghost_to_erase; // RemovedElementsEvent remove_elem(mesh); // auto & new_numberings = remove_elem.getNewNumbering(); // Element element; // element.ghost_type = _ghost; // for (auto & type : mesh.elementTypes(spatial_dimension, _ghost)) { // element.type = type; // UInt nb_ghost_elem = mesh.getNbElement(type, _ghost); // // UInt nb_ghost_elem_protected = 0; // // try { // // nb_ghost_elem_protected = nb_ghost_protected(type, _ghost); // // } catch (...) { // // } // if (!new_numberings.exists(type, _ghost)) // new_numberings.alloc(nb_ghost_elem, 1, type, _ghost); // else // new_numberings(type, _ghost).resize(nb_ghost_elem); // Array<UInt> & new_numbering = new_numberings(type, _ghost); // for (UInt g = 0; g < nb_ghost_elem; ++g) { // element.element = g; // if (element.element >= nb_ghost_elem_protected && // relevant_ghost_elements.find(element) == // relevant_ghost_elements.end()) { // remove_elem.getList().push_back(element); // new_numbering(element.element) = UInt(-1); // } // } // /// renumber remaining ghosts // UInt ng = 0; // for (UInt g = 0; g < nb_ghost_elem; ++g) { // if (new_numbering(g) != UInt(-1)) { // new_numbering(g) = ng; // ++ng; // } // } // } // for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost)) { // UInt nb_elem = mesh.getNbElement(type, _not_ghost); // if (!new_numberings.exists(type, _not_ghost)) // new_numberings.alloc(nb_elem, 1, type, _not_ghost); // Array<UInt> & new_numbering = new_numberings(type, _not_ghost); // for (UInt e = 0; e < nb_elem; ++e) { // new_numbering(e) = e; // } // } // mesh.sendEvent(remove_elem); } /* -------------------------------------------------------------------------- */ void NonLocalManager::onElementsRemoved( const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { FEEngine & fee = this->model.getFEEngine(); this->removeIntegrationPointsFromMap( event.getNewNumbering(), spatial_dimension, integration_points_positions, fee, _ek_regular); this->removeIntegrationPointsFromMap(event.getNewNumbering(), 1, volumes, fee, _ek_regular); /// loop over all the neighborhoods and call onElementsRemoved auto global_neighborhood_it = global_neighborhoods.begin(); NeighborhoodMap::iterator it; for (; global_neighborhood_it != global_neighborhoods.end(); ++global_neighborhood_it) { it = neighborhoods.find(*global_neighborhood_it); if (it != neighborhoods.end()) it->second->onElementsRemoved(element_list, new_numbering, event); else dummy_synchronizers[*global_neighborhood_it]->onElementsRemoved( element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::onElementsAdded(const Array<Element> &, const NewElementsEvent &) { this->resizeElementTypeMap(1, volumes, model.getFEEngine()); this->resizeElementTypeMap(spatial_dimension, integration_points_positions, model.getFEEngine()); } /* -------------------------------------------------------------------------- */ void NonLocalManager::resizeElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { Mesh & mesh = this->model.getMesh(); for (auto gt : ghost_types) { for (auto type : mesh.elementTypes(spatial_dimension, gt, el_kind)) { UInt nb_element = mesh.getNbElement(type, gt); UInt nb_quads = fee.getNbIntegrationPoints(type, gt); if (!element_map.exists(type, gt)) element_map.alloc(nb_element * nb_quads, nb_component, type, gt); else element_map(type, gt).resize(nb_element * nb_quads); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::removeIntegrationPointsFromMap( const ElementTypeMapArray<UInt> & new_numbering, UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { for (auto gt : ghost_types) { for (auto type : new_numbering.elementTypes(_all_dimensions, gt, el_kind)) { if (element_map.exists(type, gt)) { const Array<UInt> & renumbering = new_numbering(type, gt); Array<Real> & vect = element_map(type, gt); UInt nb_quad_per_elem = fee.getNbIntegrationPoints(type, gt); Array<Real> tmp(renumbering.size() * nb_quad_per_elem, nb_component); AKANTU_DEBUG_ASSERT( tmp.size() == vect.size(), "Something strange append some mater was created or disappeared in " << vect.getID() << "(" << vect.size() << "!=" << tmp.size() << ") " "!!"); UInt new_size = 0; for (UInt i = 0; i < renumbering.size(); ++i) { UInt new_i = renumbering(i); if (new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component * nb_quad_per_elem, vect.storage() + i * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem * sizeof(Real)); ++new_size; } } tmp.resize(new_size * nb_quad_per_elem); vect.copy(tmp); } } } } /* -------------------------------------------------------------------------- */ UInt NonLocalManager::getNbData(const Array<Element> & elements, const ID & id) const { UInt size = 0; UInt nb_quadrature_points = this->model.getNbIntegrationPoints(elements); auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); size += it->second->nb_component * sizeof(Real) * nb_quadrature_points; return size; } /* -------------------------------------------------------------------------- */ void NonLocalManager::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const ID & id) const { auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor<Element>::packElementalDataHelper<Real>( it->second->local, buffer, elements, true, this->model.getFEEngine()); } /* -------------------------------------------------------------------------- */ void NonLocalManager::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const ID & id) const { auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor<Element>::unpackElementalDataHelper<Real>( it->second->local, buffer, elements, true, this->model.getFEEngine()); } } // namespace akantu diff --git a/src/model/common/non_local_toolbox/non_local_manager.hh b/src/model/common/non_local_toolbox/non_local_manager.hh index cca5c52f1..775fb4982 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.hh +++ b/src/model/common/non_local_toolbox/non_local_manager.hh @@ -1,292 +1,292 @@ /** * @file non_local_manager.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Classes that manages all the non-local neighborhoods * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "communication_buffer.hh" #include "data_accessor.hh" #include "mesh_events.hh" #include "non_local_manager_callback.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #include <map> #include <set> /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_MANAGER_HH__ #define __AKANTU_NON_LOCAL_MANAGER_HH__ namespace akantu { class Model; class NonLocalNeighborhoodBase; class GridSynchronizer; class SynchronizerRegistry; class IntegrationPoint; template <typename T> class SpatialGrid; class FEEngine; } // namespace akantu namespace akantu { class NonLocalManager : protected Memory, public MeshEventHandler, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLocalManager(Model & model, NonLocalManagerCallback & callback, const ID & id = "non_local_manager", const MemoryID & memory_id = 0); ~NonLocalManager() override; using NeighborhoodMap = std::map<ID, std::unique_ptr<NonLocalNeighborhoodBase>>; /* ------------------------------------------------------------------------ */ /* Methods */ /* ----------------------------------------------------------------------- */ public: /// register a new internal needed for the weight computations ElementTypeMapReal & registerWeightFunctionInternal(const ID & field_name); /// register a non-local variable void registerNonLocalVariable(const ID & variable_name, const ID & nl_variable_name, UInt nb_component); /// register non-local neighborhood inline void registerNeighborhood(const ID & neighborhood, const ID & weight_func_id); // void registerNonLocalManagerCallback(NonLocalManagerCallback & callback); /// average the internals and compute the non-local stresses virtual void computeAllNonLocalStresses(); /// initialize the non-local manager: compute pair lists and weights for all /// neighborhoods virtual void initialize(); /// synchronize once on a given tag using the neighborhoods synchronizer void synchronize(DataAccessor<Element> & data_accessor, const SynchronizationTag &); protected: /// create the grid synchronizers for each neighborhood void createNeighborhoodSynchronizers(); /// compute the weights in each neighborhood for non-local averaging void computeWeights(); /// compute the weights in each neighborhood for non-local averaging void updatePairLists(); /// average the non-local variables void averageInternals(const GhostType & ghost_type = _not_ghost); /// update the flattened version of the weight function internals void updateWeightFunctionInternals(); protected: /// create a new neighborhood for a given domain ID void createNeighborhood(const ID & weight_func, const ID & neighborhood); /// set the values of the jacobians void setJacobians(const FEEngine & fe_engine, const ElementKind & kind); /// allocation of eelment type maps // void initElementTypeMap(UInt nb_component, // ElementTypeMapReal & element_map, // const FEEngine & fe_engine, // const ElementKind el_kind = _ek_regular); /// resizing of element type maps void resizeElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind = _ek_regular); /// remove integration points from element type maps void removeIntegrationPointsFromMap( const ElementTypeMapArray<UInt> & new_numbering, UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind = _ek_regular); /// allocate the non-local variables void initNonLocalVariables(); /// cleanup unneccessary ghosts void cleanupExtraGhostElements(); // ElementTypeMap<UInt> & nb_ghost_protected); /* ------------------------------------------------------------------------ */ /* DataAccessor kind of interface */ /* ------------------------------------------------------------------------ */ public: /// get Nb data for synchronization in parallel UInt getNbData(const Array<Element> & elements, const ID & id) const; /// pack data for synchronization in parallel void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const ID & id) const; /// unpack data for synchronization in parallel void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const ID & id) const; /* ------------------------------------------------------------------------ */ /* MeshEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; void onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) override; void onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) override {} void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) override {} void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, const RemovedNodesEvent &) override{}; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); AKANTU_GET_MACRO(Model, model, const Model &); AKANTU_GET_MACRO_NOT_CONST(Model, model, Model &); AKANTU_GET_MACRO_NOT_CONST(Volumes, volumes, ElementTypeMapReal &) AKANTU_GET_MACRO(NbStressCalls, compute_stress_calls, UInt); /// return the fem object associated with a provided name inline NonLocalNeighborhoodBase & getNeighborhood(const ID & name) const; inline const Array<Real> & getJacobians(const ElementType & type, const GhostType & ghost_type) { return *jacobians(type, ghost_type); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// the spatial dimension const UInt spatial_dimension; protected: /// the non-local neighborhoods present NeighborhoodMap neighborhoods; /// list of all the non-local materials in the model // std::vector<ID> non_local_materials; struct NonLocalVariable { NonLocalVariable(const ID & variable_name, const ID & nl_variable_name, const ID & id, UInt nb_component) : local(variable_name, id, 0), non_local(nl_variable_name, id, 0), nb_component(nb_component) {} ElementTypeMapReal local; ElementTypeMapReal non_local; UInt nb_component; }; /// the non-local variables associated to a certain neighborhood std::map<ID, std::unique_ptr<NonLocalVariable>> non_local_variables; /// reference to the model Model & model; /// jacobians for all the elements in the mesh ElementTypeMap<const Array<Real> *> jacobians; /// store the position of the quadrature points ElementTypeMapReal integration_points_positions; /// store the volume of each quadrature point for the non-local weight /// normalization ElementTypeMapReal volumes; /// counter for computeStress calls UInt compute_stress_calls; /// map to store weight function types from input file std::map<ID, ParserSection> weight_function_types; /// map to store the internals needed by the weight functions std::map<ID, std::unique_ptr<ElementTypeMapReal>> weight_function_internals; /* -------------------------------------------------------------------------- */ /// the following are members needed to make this processor participate in the /// grid creation of neighborhoods he doesn't own as a member. For details see /// createGridSynchronizers function /// synchronizer registry for dummy grid synchronizers std::unique_ptr<SynchronizerRegistry> dummy_registry; /// map of dummy synchronizers std::map<ID, std::unique_ptr<GridSynchronizer>> dummy_synchronizers; /// dummy spatial grid std::unique_ptr<SpatialGrid<IntegrationPoint>> dummy_grid; /// create a set of all neighborhoods present in the simulation std::set<ID> global_neighborhoods; class DummyDataAccessor : public DataAccessor<Element> { public: inline UInt getNbData(const Array<Element> &, const SynchronizationTag &) const override { return 0; }; inline void packData(CommunicationBuffer &, const Array<Element> &, const SynchronizationTag &) const override{}; inline void unpackData(CommunicationBuffer &, const Array<Element> &, const SynchronizationTag &) override{}; }; DummyDataAccessor dummy_accessor; /* ------------------------------------------------------------------------ */ NonLocalManagerCallback * callback; }; } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "non_local_manager_inline_impl.cc" #endif /* __AKANTU_NON_LOCAL_MANAGER_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_manager_callback.hh b/src/model/common/non_local_toolbox/non_local_manager_callback.hh index f29671b4d..b44a520e8 100644 --- a/src/model/common/non_local_toolbox/non_local_manager_callback.hh +++ b/src/model/common/non_local_toolbox/non_local_manager_callback.hh @@ -1,66 +1,68 @@ /** * @file non_local_manager_callback.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Sun Jul 09 2017 + * @date creation: Fri Jul 21 2017 + * @date last modification: Tue Sep 19 2017 * - * @brief Callback functions for the non local manager + * @brief Callback functions for the non local manager * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_type_map.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_MANAGER_CALLBACK_HH__ #define __AKANTU_NON_LOCAL_MANAGER_CALLBACK_HH__ namespace akantu { class NonLocalManager; } // namespace akantu namespace akantu { class NonLocalManagerCallback { public: virtual void initializeNonLocal() {} /* ------------------------------------------------------------------------ */ virtual void insertIntegrationPointsInNeighborhoods(const GhostType & ghost_type) = 0; virtual void computeNonLocalStresses(const GhostType & ghost_type) = 0; /// update the values of the non local internal virtual void updateLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) = 0; /// copy the results of the averaging in the materials virtual void updateNonLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) = 0; }; } // namespace akantu #endif /* __AKANTU_NON_LOCAL_MANAGER_CALLBACK_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc b/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc index 8b63d0073..3649b1019 100644 --- a/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc +++ b/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc @@ -1,69 +1,68 @@ /** * @file non_local_manager_inline_impl.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Mon Sep 11 2017 * * @brief inline implementation of non-local manager functions * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_MANAGER_INLINE_IMPL_CC__ #define __AKANTU_NON_LOCAL_MANAGER_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline void NonLocalManager::registerNeighborhood(const ID & neighborhood, const ID & weight_func_id) { /// check if neighborhood has already been created auto it = neighborhoods.find(neighborhood); if (it == neighborhoods.end()) { this->createNeighborhood(weight_func_id, neighborhood); } } /* -------------------------------------------------------------------------- */ inline NonLocalNeighborhoodBase & NonLocalManager::getNeighborhood(const ID & name) const { AKANTU_DEBUG_IN(); auto it = neighborhoods.find(name); AKANTU_DEBUG_ASSERT(it != neighborhoods.end(), "The neighborhood " << name << " is not registered"); AKANTU_DEBUG_OUT(); return *(it->second); } } // namespace akantu #endif /* __AKANTU_NON_LOCAL_MANAGER_INLINE_IMPL_CC__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood.hh b/src/model/common/non_local_toolbox/non_local_neighborhood.hh index a847e9947..1dfd507e0 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood.hh @@ -1,136 +1,135 @@ /** * @file non_local_neighborhood.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Non-local neighborhood for non-local averaging based on * weight function * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_HH__ /* -------------------------------------------------------------------------- */ #include "base_weight_function.hh" #include "non_local_neighborhood_base.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class NonLocalManager; class BaseWeightFunction; } // namespace akantu namespace akantu { template <class WeightFunction = BaseWeightFunction> class NonLocalNeighborhood : public NonLocalNeighborhoodBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLocalNeighborhood(NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates, const ID & id = "neighborhood", const MemoryID & memory_id = 0); ~NonLocalNeighborhood() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// compute the weights for non-local averaging void computeWeights() override; /// save the pair of weights in a file void saveWeights(const std::string & filename) const override; /// compute the non-local counter part for a given element type map // compute the non-local counter part for a given element type map void weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const override; /// update the weights based on the weight function void updateWeights() override; /// register a new non-local variable in the neighborhood // void registerNonLocalVariable(const ID & id); protected: template <class Func> inline void foreach_weight(const GhostType & ghost_type, Func && func); template <class Func> inline void foreach_weight(const GhostType & ghost_type, Func && func) const; inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; /* ------------------------------------------------------------------------ */ /* Accessor */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(NonLocalManager, non_local_manager, const NonLocalManager &); AKANTU_GET_MACRO_NOT_CONST(NonLocalManager, non_local_manager, NonLocalManager &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// Pointer to non-local manager class NonLocalManager & non_local_manager; /// the weights associated to the pairs std::array<std::unique_ptr<Array<Real>>, 2> pair_weight; /// weight function std::unique_ptr<WeightFunction> weight_function; }; } // namespace akantu /* -------------------------------------------------------------------------- */ /* Implementation of template functions */ /* -------------------------------------------------------------------------- */ #include "non_local_neighborhood_tmpl.hh" /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "non_local_neighborhood_inline_impl.cc" #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc b/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc index 81cf8934a..3e98bcc82 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc @@ -1,117 +1,117 @@ /** * @file non_local_neighborhood_base.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sat Sep 26 2015 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Fri Dec 08 2017 * * @brief Implementation of non-local neighborhood base * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_local_neighborhood_base.hh" #include "grid_synchronizer.hh" #include "model.hh" /* -------------------------------------------------------------------------- */ #include <memory> namespace akantu { /* -------------------------------------------------------------------------- */ NonLocalNeighborhoodBase::NonLocalNeighborhoodBase( Model & model, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : NeighborhoodBase(model, quad_coordinates, id, memory_id), Parsable(ParserType::_non_local, id) { AKANTU_DEBUG_IN(); this->registerParam("radius", neighborhood_radius, 100., _pat_parsable | _pat_readable, "Non local radius"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NonLocalNeighborhoodBase::~NonLocalNeighborhoodBase() = default; /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::createGridSynchronizer() { this->is_creating_grid = true; this->grid_synchronizer = std::make_unique<GridSynchronizer>( this->model.getMesh(), *spatial_grid, *this, std::set<SynchronizationTag>{_gst_mnl_weight, _gst_mnl_for_average}, std::string(getID() + ":grid_synchronizer"), this->memory_id, false); this->is_creating_grid = false; } /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::synchronize( DataAccessor<Element> & data_accessor, const SynchronizationTag & tag) { if (not grid_synchronizer) return; grid_synchronizer->synchronizeOnce(data_accessor, tag); } /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::cleanupExtraGhostElements( std::set<Element> & relevant_ghost_elements) { for (auto && pair : pair_list[_ghost]) { const auto & q2 = pair.second; relevant_ghost_elements.insert(q2); } Array<Element> ghosts_to_erase(0); auto & mesh = this->model.getMesh(); Element element; element.ghost_type = _ghost; auto end = relevant_ghost_elements.end(); for (auto & type : mesh.elementTypes(spatial_dimension, _ghost)) { element.type = type; UInt nb_ghost_elem = mesh.getNbElement(type, _ghost); for (UInt g = 0; g < nb_ghost_elem; ++g) { element.element = g; if (relevant_ghost_elements.find(element) == end) { ghosts_to_erase.push_back(element); } } } /// remove the unneccessary ghosts from the synchronizer // this->grid_synchronizer->removeElements(ghosts_to_erase); mesh.eraseElements(ghosts_to_erase); } /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::registerNonLocalVariable(const ID & id) { this->non_local_variables.insert(id); } } // namespace akantu diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh index 3d6cfbe06..238705e74 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh @@ -1,128 +1,129 @@ /** * @file non_local_neighborhood_base.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sat Sep 26 2015 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Non-local neighborhood base class * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ namespace akantu { class Model; } /* -------------------------------------------------------------------------- */ namespace akantu { class NonLocalNeighborhoodBase : public NeighborhoodBase, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLocalNeighborhoodBase(Model & model, const ElementTypeMapReal & quad_coordinates, const ID & id = "non_local_neighborhood", const MemoryID & memory_id = 0); ~NonLocalNeighborhoodBase() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// create grid synchronizer and exchange ghost cells void createGridSynchronizer() override; void synchronize(DataAccessor<Element> & data_accessor, const SynchronizationTag & tag) override; /// compute weights, for instance needed for non-local damage computation virtual void computeWeights(){}; // compute the non-local counter part for a given element type map virtual void weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const = 0; /// update the weights for the non-local averaging virtual void updateWeights() = 0; /// update the weights for the non-local averaging virtual void saveWeights(const std::string &) const { AKANTU_TO_IMPLEMENT(); } /// register a new non-local variable in the neighborhood virtual void registerNonLocalVariable(const ID & id); /// clean up the unneccessary ghosts void cleanupExtraGhostElements(std::set<Element> & relevant_ghost_elements); protected: /// create the grid void createGrid(); /* -------------------------------------------------------------------------- */ /* DataAccessor inherited members */ /* -------------------------------------------------------------------------- */ public: inline UInt getNbData(const Array<Element> &, const SynchronizationTag &) const override { return 0; } inline void packData(CommunicationBuffer &, const Array<Element> &, const SynchronizationTag &) const override {} inline void unpackData(CommunicationBuffer &, const Array<Element> &, const SynchronizationTag &) override {} /* -------------------------------------------------------------------------- */ /* Accessors */ /* -------------------------------------------------------------------------- */ public: AKANTU_GET_MACRO(NonLocalVariables, non_local_variables, const std::set<ID> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of non-local variables associated to the neighborhood std::set<ID> non_local_variables; }; } // namespace akantu #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc b/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc index 389da6687..50e9cf512 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc @@ -1,86 +1,87 @@ /** * @file non_local_neighborhood_inline_impl.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Oct 06 2015 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Thu Jul 06 2017 * * @brief Implementation of inline functions of non-local neighborhood class * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "non_local_neighborhood.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_INLINE_IMPL_CC__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class WeightFunction> inline UInt NonLocalNeighborhood<WeightFunction>::getNbData( const Array<Element> & elements, const SynchronizationTag & tag) const { UInt size = 0; if (tag == _gst_mnl_for_average) { for (auto & variable_id : non_local_variables) { size += this->non_local_manager.getNbData(elements, variable_id); } } size += this->weight_function->getNbData(elements, tag); return size; } /* -------------------------------------------------------------------------- */ template <class WeightFunction> inline void NonLocalNeighborhood<WeightFunction>::packData( CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_mnl_for_average) { for (auto & variable_id : non_local_variables) { this->non_local_manager.packData(buffer, elements, variable_id); } } this->weight_function->packData(buffer, elements, tag); } /* -------------------------------------------------------------------------- */ template <class WeightFunction> inline void NonLocalNeighborhood<WeightFunction>::unpackData( CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_mnl_for_average) { for (auto & variable_id : non_local_variables) { this->non_local_manager.unpackData(buffer, elements, variable_id); } } this->weight_function->unpackData(buffer, elements, tag); } } // namespace akantu #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_INLINE_IMPL_CC__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh index e6283a065..51ea76127 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh @@ -1,276 +1,276 @@ /** * @file non_local_neighborhood_tmpl.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Sep 28 2015 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of class non-local neighborhood * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "non_local_manager.hh" #include "non_local_neighborhood.hh" /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class WeightFunction> template <class Func> inline void NonLocalNeighborhood<WeightFunction>::foreach_weight( const GhostType & ghost_type, Func && func) { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward<decltype(func)>(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template <class WeightFunction> template <class Func> inline void NonLocalNeighborhood<WeightFunction>::foreach_weight( const GhostType & ghost_type, Func && func) const { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward<decltype(func)>(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template <class WeightFunction> NonLocalNeighborhood<WeightFunction>::NonLocalNeighborhood( NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : NonLocalNeighborhoodBase(manager.getModel(), quad_coordinates, id, memory_id), non_local_manager(manager) { AKANTU_DEBUG_IN(); this->weight_function = std::make_unique<WeightFunction>(manager); this->registerSubSection(ParserType::_weight_function, "weight_parameter", *weight_function); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class WeightFunction> NonLocalNeighborhood<WeightFunction>::~NonLocalNeighborhood() = default; /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::computeWeights() { AKANTU_DEBUG_IN(); this->weight_function->setRadius(this->neighborhood_radius); Vector<Real> q1_coord(this->spatial_dimension); Vector<Real> q2_coord(this->spatial_dimension); UInt nb_weights_per_pair = 2; /// w1: q1->q2, w2: q2->q1 /// get the elementtypemap for the neighborhood volume for each quadrature /// point ElementTypeMapReal & quadrature_points_volumes = this->non_local_manager.getVolumes(); /// update the internals of the weight function if applicable (not /// all the weight functions have internals and do noting in that /// case) weight_function->updateInternals(); for (auto ghost_type : ghost_types) { /// allocate the array to store the weight, if it doesn't exist already if (!(pair_weight[ghost_type])) { pair_weight[ghost_type] = std::make_unique<Array<Real>>(0, nb_weights_per_pair); } /// resize the array to the correct size pair_weight[ghost_type]->resize(pair_list[ghost_type].size()); /// set entries to zero pair_weight[ghost_type]->clear(); /// loop over all pairs in the current pair list array and their /// corresponding weights auto first_pair = pair_list[ghost_type].begin(); auto last_pair = pair_list[ghost_type].end(); auto weight_it = pair_weight[ghost_type]->begin(nb_weights_per_pair); // Compute the weights for (; first_pair != last_pair; ++first_pair, ++weight_it) { Vector<Real> & weight = *weight_it; const IntegrationPoint & q1 = first_pair->first; const IntegrationPoint & q2 = first_pair->second; /// get the coordinates for the given pair of quads auto coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(this->spatial_dimension); q1_coord = coords_type_1_it[q1.global_num]; auto coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(this->spatial_dimension); q2_coord = coords_type_2_it[q2.global_num]; Array<Real> & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); const Array<Real> & jacobians_2 = this->non_local_manager.getJacobians(q2.type, q2.ghost_type); const Real & q2_wJ = jacobians_2(q2.global_num); /// compute distance between the two quadrature points Real r = q1_coord.distance(q2_coord); /// compute the weight for averaging on q1 based on the distance Real w1 = this->weight_function->operator()(r, q1, q2); weight(0) = q2_wJ * w1; quad_volumes_1(q1.global_num) += weight(0); if (q2.ghost_type != _ghost && q1.global_num != q2.global_num) { const Array<Real> & jacobians_1 = this->non_local_manager.getJacobians(q1.type, q1.ghost_type); Array<Real> & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); /// compute the weight for averaging on q2 const Real & q1_wJ = jacobians_1(q1.global_num); Real w2 = this->weight_function->operator()(r, q2, q1); weight(1) = q1_wJ * w2; quad_volumes_2(q2.global_num) += weight(1); } else weight(1) = 0.; } } /// normalize the weights for (auto ghost_type : ghost_types) { foreach_weight(ghost_type, [&](const auto & q1, const auto & q2, auto & weight) { auto & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); auto & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); Real q1_volume = quad_volumes_1(q1.global_num); auto ghost_type2 = q2.ghost_type; weight(0) *= 1. / q1_volume; if (ghost_type2 != _ghost) { Real q2_volume = quad_volumes_2(q2.global_num); weight(1) *= 1. / q2_volume; } }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::saveWeights( const std::string & filename) const { std::ofstream pout; std::stringstream sstr; const Communicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { auto ghost_type = (GhostType)gt; AKANTU_DEBUG_ASSERT((pair_weight[ghost_type]), "the weights have not been computed yet"); Array<Real> & weights = *(pair_weight[ghost_type]); auto weights_it = weights.begin(2); for (UInt i = 0; i < weights.size(); ++i, ++weights_it) pout << "w1: " << (*weights_it)(0) << " w2: " << (*weights_it)(1) << std::endl; } } /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::weightedAverageOnNeighbours( const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const { auto it = non_local_variables.find(accumulated.getName()); // do averaging only for variables registered in the neighborhood if (it == non_local_variables.end()) return; foreach_weight( ghost_type2, [ghost_type2, nb_degree_of_freedom, &to_accumulate, &accumulated](const auto & q1, const auto & q2, auto & weight) { const Vector<Real> to_acc_1 = to_accumulate(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; const Vector<Real> to_acc_2 = to_accumulate(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; Vector<Real> acc_1 = accumulated(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; Vector<Real> acc_2 = accumulated(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; acc_1 += weight(0) * to_acc_2; if (ghost_type2 != _ghost) { acc_2 += weight(1) * to_acc_1; } }); } /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::updateWeights() { // Update the weights for the non local variable averaging if (this->weight_function->getUpdateRate() && (this->non_local_manager.getNbStressCalls() % this->weight_function->getUpdateRate() == 0)) { SynchronizerRegistry::synchronize(_gst_mnl_weight); this->computeWeights(); } } } // namespace akantu #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL__ */ diff --git a/src/model/dof_manager.cc b/src/model/dof_manager.cc index 7aaa2fccc..9f282345d 100644 --- a/src/model/dof_manager.cc +++ b/src/model/dof_manager.cc @@ -1,604 +1,605 @@ /** * @file dof_manager.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 12 09:52:30 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of the common parts of the DOFManagers * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager.hh" #include "communicator.hh" #include "element_group.hh" #include "mesh.hh" #include "mesh_utils.hh" #include "node_group.hh" #include "non_linear_solver.hh" #include "sparse_matrix.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #include <memory> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ DOFManager::DOFManager(const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), communicator(Communicator::getStaticCommunicator()) {} /* -------------------------------------------------------------------------- */ DOFManager::DOFManager(Mesh & mesh, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), mesh(&mesh), local_system_size(0), pure_local_system_size(0), system_size(0), communicator(mesh.getCommunicator()) { this->mesh->registerEventHandler(*this, _ehp_dof_manager); } /* -------------------------------------------------------------------------- */ DOFManager::~DOFManager() = default; /* -------------------------------------------------------------------------- */ // void DOFManager::getEquationsNumbers(const ID &, Array<UInt> &) { // AKANTU_TO_IMPLEMENT(); // } /* -------------------------------------------------------------------------- */ std::vector<ID> DOFManager::getDOFIDs() const { std::vector<ID> keys; for (const auto & dof_data : this->dofs) keys.push_back(dof_data.first); return keys; } /* -------------------------------------------------------------------------- */ void DOFManager::assembleElementalArrayLocalArray( const Array<Real> & elementary_vect, Array<Real> & array_assembeled, const ElementType & type, const GhostType & ghost_type, Real scale_factor, const Array<UInt> & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_element; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; UInt * filter_it = nullptr; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); filter_it = filter_elements.storage(); } else { nb_element = this->mesh->getNbElement(type, ghost_type); } AKANTU_DEBUG_ASSERT(elementary_vect.size() == nb_element, "The vector elementary_vect(" << elementary_vect.getID() << ") has not the good size."); const Array<UInt> & connectivity = this->mesh->getConnectivity(type, ghost_type); // Array<UInt>::const_vector_iterator conn_begin = // connectivity.begin(nb_nodes_per_element); // Array<UInt>::const_vector_iterator conn_it = conn_begin; Array<Real>::const_matrix_iterator elem_it = elementary_vect.begin(nb_degree_of_freedom, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++elem_it) { UInt element = el; if (filter_it != nullptr) { // conn_it = conn_begin + *filter_it; element = *filter_it; } // const Vector<UInt> & conn = *conn_it; const Matrix<Real> & elemental_val = *elem_it; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt offset_node = connectivity(element, n) * nb_degree_of_freedom; Vector<Real> assemble(array_assembeled.storage() + offset_node, nb_degree_of_freedom); Vector<Real> elem_val = elemental_val(n); assemble.aXplusY(elem_val, scale_factor); } if (filter_it != nullptr) ++filter_it; // else // ++conn_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManager::assembleElementalArrayToResidual( const ID & dof_id, const Array<Real> & elementary_vect, const ElementType & type, const GhostType & ghost_type, Real scale_factor, const Array<UInt> & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; Array<Real> array_localy_assembeled(this->mesh->getNbNodes(), nb_degree_of_freedom); array_localy_assembeled.clear(); this->assembleElementalArrayLocalArray( elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor, filter_elements); this->assembleToResidual(dof_id, array_localy_assembeled, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManager::assembleElementalArrayToLumpedMatrix( const ID & dof_id, const Array<Real> & elementary_vect, const ID & lumped_mtx, const ElementType & type, const GhostType & ghost_type, Real scale_factor, const Array<UInt> & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; Array<Real> array_localy_assembeled(this->mesh->getNbNodes(), nb_degree_of_freedom); array_localy_assembeled.clear(); this->assembleElementalArrayLocalArray( elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor, filter_elements); this->assembleToLumpedMatrix(dof_id, array_localy_assembeled, lumped_mtx, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManager::assembleMatMulDOFsToResidual(const ID & A_id, Real scale_factor) { for (auto & pair : this->dofs) { const auto & dof_id = pair.first; auto & dof_data = *pair.second; this->assembleMatMulVectToResidual(dof_id, A_id, *dof_data.dof, scale_factor); } } /* -------------------------------------------------------------------------- */ DOFManager::DOFData::DOFData(const ID & dof_id) : support_type(_dst_generic), group_support("__mesh__"), dof(nullptr), blocked_dofs(nullptr), increment(nullptr), previous(nullptr), solution(0, 1, dof_id + ":solution"), local_equation_number(0, 1, dof_id + ":local_equation_number") {} /* -------------------------------------------------------------------------- */ DOFManager::DOFData::~DOFData() = default; /* -------------------------------------------------------------------------- */ DOFManager::DOFData & DOFManager::getNewDOFData(const ID & dof_id) { auto it = this->dofs.find(dof_id); if (it != this->dofs.end()) { AKANTU_EXCEPTION("This dof array has already been registered"); } std::unique_ptr<DOFData> dofs_storage = std::make_unique<DOFData>(dof_id); this->dofs[dof_id] = std::move(dofs_storage); return *dofs_storage; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) { DOFData & dofs_storage = this->getDOFData(dof_id); dofs_storage.dof = &dofs_array; UInt nb_local_dofs = 0; UInt nb_pure_local = 0; const DOFSupportType & support_type = dofs_storage.support_type; switch (support_type) { case _dst_nodal: { UInt nb_nodes = 0; const ID & group = dofs_storage.group_support; NodeGroup * node_group = nullptr; if (group == "__mesh__") { nb_nodes = this->mesh->getNbNodes(); } else { node_group = &this->mesh->getElementGroup(group).getNodeGroup(); nb_nodes = node_group->size(); } nb_local_dofs = nb_nodes; AKANTU_DEBUG_ASSERT( dofs_array.size() == nb_local_dofs, "The array of dof is too shot to be associated to nodes."); for (UInt n = 0; n < nb_nodes; ++n) { UInt node = n; if (node_group) node = node_group->getNodes()(n); nb_pure_local += this->mesh->isLocalOrMasterNode(node) ? 1 : 0; } nb_pure_local *= dofs_array.getNbComponent(); nb_local_dofs *= dofs_array.getNbComponent(); break; } case _dst_generic: { nb_local_dofs = nb_pure_local = dofs_array.size() * dofs_array.getNbComponent(); break; } default: { AKANTU_EXCEPTION("This type of dofs is not handled yet."); } } this->pure_local_system_size += nb_pure_local; this->local_system_size += nb_local_dofs; communicator.allReduce(nb_pure_local, SynchronizerOperation::_sum); this->system_size += nb_pure_local; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const DOFSupportType & support_type) { DOFData & dofs_storage = this->getNewDOFData(dof_id); dofs_storage.support_type = support_type; this->registerDOFsInternal(dof_id, dofs_array); } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const ID & support_group) { DOFData & dofs_storage = this->getNewDOFData(dof_id); dofs_storage.support_type = _dst_nodal; dofs_storage.group_support = support_group; this->registerDOFsInternal(dof_id, dofs_array); } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsPrevious(const ID & dof_id, Array<Real> & array) { DOFData & dof = this->getDOFData(dof_id); if (dof.previous != nullptr) { AKANTU_EXCEPTION("The previous dofs array for " << dof_id << " has already been registered"); } dof.previous = &array; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsIncrement(const ID & dof_id, Array<Real> & array) { DOFData & dof = this->getDOFData(dof_id); if (dof.increment != nullptr) { AKANTU_EXCEPTION("The dofs increment array for " << dof_id << " has already been registered"); } dof.increment = &array; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsDerivative(const ID & dof_id, UInt order, Array<Real> & dofs_derivative) { DOFData & dof = this->getDOFData(dof_id); std::vector<Array<Real> *> & derivatives = dof.dof_derivatives; if (derivatives.size() < order) { derivatives.resize(order, nullptr); } else { if (derivatives[order - 1] != nullptr) { AKANTU_EXCEPTION("The dof derivatives of order " << order << " already been registered for this dof (" << dof_id << ")"); } } derivatives[order - 1] = &dofs_derivative; } /* -------------------------------------------------------------------------- */ void DOFManager::registerBlockedDOFs(const ID & dof_id, Array<bool> & blocked_dofs) { DOFData & dof = this->getDOFData(dof_id); if (dof.blocked_dofs != nullptr) { AKANTU_EXCEPTION("The blocked dofs array for " << dof_id << " has already been registered"); } dof.blocked_dofs = &blocked_dofs; } /* -------------------------------------------------------------------------- */ void DOFManager::splitSolutionPerDOFs() { auto it = this->dofs.begin(); auto end = this->dofs.end(); for (; it != end; ++it) { DOFData & dof_data = *it->second; dof_data.solution.resize(dof_data.dof->size() * dof_data.dof->getNbComponent()); this->getSolutionPerDOFs(it->first, dof_data.solution); } } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManager::registerSparseMatrix(const ID & matrix_id, std::unique_ptr<SparseMatrix> & matrix) { SparseMatricesMap::const_iterator it = this->matrices.find(matrix_id); if (it != this->matrices.end()) { AKANTU_EXCEPTION("The matrix " << matrix_id << " already exists in " << this->id); } SparseMatrix & ret = *matrix; this->matrices[matrix_id] = std::move(matrix); return ret; } /* -------------------------------------------------------------------------- */ /// Get an instance of a new SparseMatrix Array<Real> & DOFManager::getNewLumpedMatrix(const ID & id) { ID matrix_id = this->id + ":lumped_mtx:" + id; LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(matrix_id); if (it != this->lumped_matrices.end()) { AKANTU_EXCEPTION("The lumped matrix " << matrix_id << " already exists in " << this->id); } auto mtx = std::make_unique<Array<Real>>(this->local_system_size, 1, matrix_id); this->lumped_matrices[matrix_id] = std::move(mtx); return *this->lumped_matrices[matrix_id]; } /* -------------------------------------------------------------------------- */ NonLinearSolver & DOFManager::registerNonLinearSolver( const ID & non_linear_solver_id, std::unique_ptr<NonLinearSolver> & non_linear_solver) { NonLinearSolversMap::const_iterator it = this->non_linear_solvers.find(non_linear_solver_id); if (it != this->non_linear_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << non_linear_solver_id << " already exists in " << this->id); } NonLinearSolver & ret = *non_linear_solver; this->non_linear_solvers[non_linear_solver_id] = std::move(non_linear_solver); return ret; } /* -------------------------------------------------------------------------- */ TimeStepSolver & DOFManager::registerTimeStepSolver( const ID & time_step_solver_id, std::unique_ptr<TimeStepSolver> & time_step_solver) { TimeStepSolversMap::const_iterator it = this->time_step_solvers.find(time_step_solver_id); if (it != this->time_step_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << time_step_solver_id << " already exists in " << this->id); } TimeStepSolver & ret = *time_step_solver; this->time_step_solvers[time_step_solver_id] = std::move(time_step_solver); return ret; } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManager::getMatrix(const ID & id) { ID matrix_id = this->id + ":mtx:" + id; SparseMatricesMap::const_iterator it = this->matrices.find(matrix_id); if (it == this->matrices.end()) { AKANTU_SILENT_EXCEPTION("The matrix " << matrix_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasMatrix(const ID & id) const { ID mtx_id = this->id + ":mtx:" + id; auto it = this->matrices.find(mtx_id); return it != this->matrices.end(); } /* -------------------------------------------------------------------------- */ Array<Real> & DOFManager::getLumpedMatrix(const ID & id) { ID matrix_id = this->id + ":lumped_mtx:" + id; LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(matrix_id); if (it == this->lumped_matrices.end()) { AKANTU_SILENT_EXCEPTION("The lumped matrix " << matrix_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ const Array<Real> & DOFManager::getLumpedMatrix(const ID & id) const { ID matrix_id = this->id + ":lumped_mtx:" + id; auto it = this->lumped_matrices.find(matrix_id); if (it == this->lumped_matrices.end()) { AKANTU_SILENT_EXCEPTION("The lumped matrix " << matrix_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasLumpedMatrix(const ID & id) const { ID mtx_id = this->id + ":lumped_mtx:" + id; auto it = this->lumped_matrices.find(mtx_id); return it != this->lumped_matrices.end(); } /* -------------------------------------------------------------------------- */ NonLinearSolver & DOFManager::getNonLinearSolver(const ID & id) { ID non_linear_solver_id = this->id + ":nls:" + id; NonLinearSolversMap::const_iterator it = this->non_linear_solvers.find(non_linear_solver_id); if (it == this->non_linear_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << non_linear_solver_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasNonLinearSolver(const ID & id) const { ID solver_id = this->id + ":nls:" + id; auto it = this->non_linear_solvers.find(solver_id); return it != this->non_linear_solvers.end(); } /* -------------------------------------------------------------------------- */ TimeStepSolver & DOFManager::getTimeStepSolver(const ID & id) { ID time_step_solver_id = this->id + ":tss:" + id; TimeStepSolversMap::const_iterator it = this->time_step_solvers.find(time_step_solver_id); if (it == this->time_step_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << time_step_solver_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasTimeStepSolver(const ID & solver_id) const { ID time_step_solver_id = this->id + ":tss:" + solver_id; auto it = this->time_step_solvers.find(time_step_solver_id); return it != this->time_step_solvers.end(); } /* -------------------------------------------------------------------------- */ void DOFManager::savePreviousDOFs(const ID & dofs_id) { this->getPreviousDOFs(dofs_id).copy(this->getDOFs(dofs_id)); } /* -------------------------------------------------------------------------- */ /* Mesh Events */ /* -------------------------------------------------------------------------- */ std::pair<UInt, UInt> DOFManager::updateNodalDOFs(const ID & dof_id, const Array<UInt> & nodes_list) { auto & dof_data = this->getDOFData(dof_id); UInt nb_new_local_dofs = 0; UInt nb_new_pure_local = 0; nb_new_local_dofs = nodes_list.size(); for (const auto & node : nodes_list) { nb_new_pure_local += this->mesh->isLocalOrMasterNode(node) ? 1 : 0; } const auto & dof_array = *dof_data.dof; nb_new_pure_local *= dof_array.getNbComponent(); nb_new_local_dofs *= dof_array.getNbComponent(); this->pure_local_system_size += nb_new_pure_local; this->local_system_size += nb_new_local_dofs; UInt nb_new_global = nb_new_pure_local; communicator.allReduce(nb_new_global, SynchronizerOperation::_sum); this->system_size += nb_new_global; return std::make_pair(nb_new_local_dofs, nb_new_pure_local); } /* -------------------------------------------------------------------------- */ void DOFManager::onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent &) { for (auto & pair : this->dofs) { const auto & dof_id = pair.first; auto & dof_data = this->getDOFData(dof_id); if (dof_data.support_type != _dst_nodal) continue; const auto & group = dof_data.group_support; if (group == "__mesh__") { this->updateNodalDOFs(dof_id, nodes_list); } else { const auto & node_group = this->mesh->getElementGroup(group).getNodeGroup(); Array<UInt> new_nodes_list; for (const auto & node : nodes_list) { if (node_group.find(node) != UInt(-1)) new_nodes_list.push_back(node); } this->updateNodalDOFs(dof_id, new_nodes_list); } } } /* -------------------------------------------------------------------------- */ void DOFManager::onNodesRemoved(const Array<UInt> &, const Array<UInt> &, const RemovedNodesEvent &) {} /* -------------------------------------------------------------------------- */ void DOFManager::onElementsAdded(const Array<Element> &, const NewElementsEvent &) {} /* -------------------------------------------------------------------------- */ void DOFManager::onElementsRemoved(const Array<Element> &, const ElementTypeMapArray<UInt> &, const RemovedElementsEvent &) {} /* -------------------------------------------------------------------------- */ void DOFManager::onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) {} /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/dof_manager.hh b/src/model/dof_manager.hh index 981501a3c..4539874d8 100644 --- a/src/model/dof_manager.hh +++ b/src/model/dof_manager.hh @@ -1,475 +1,476 @@ /** * @file dof_manager.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Jul 22 11:43:43 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Class handling the different types of dofs * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "aka_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include <map> #include <set> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DOF_MANAGER_HH__ #define __AKANTU_DOF_MANAGER_HH__ namespace akantu { class TermsToAssemble; class NonLinearSolver; class TimeStepSolver; class SparseMatrix; } // namespace akantu namespace akantu { class DOFManager : protected Memory, protected MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DOFManager(const ID & id = "dof_manager", const MemoryID & memory_id = 0); DOFManager(Mesh & mesh, const ID & id = "dof_manager", const MemoryID & memory_id = 0); ~DOFManager() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ private: /// common function to help registering dofs void registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array); public: /// register an array of degree of freedom virtual void registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const DOFSupportType & support_type); /// the dof as an implied type of _dst_nodal and is defined only on a subset /// of nodes virtual void registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const ID & group_support); /// register an array of previous values of the degree of freedom virtual void registerDOFsPrevious(const ID & dof_id, Array<Real> & dofs_array); /// register an array of increment of degree of freedom virtual void registerDOFsIncrement(const ID & dof_id, Array<Real> & dofs_array); /// register an array of derivatives for a particular dof array virtual void registerDOFsDerivative(const ID & dof_id, UInt order, Array<Real> & dofs_derivative); /// register array representing the blocked degree of freedoms virtual void registerBlockedDOFs(const ID & dof_id, Array<bool> & blocked_dofs); /// Assemble an array to the global residual array virtual void assembleToResidual(const ID & dof_id, const Array<Real> & array_to_assemble, Real scale_factor = 1.) = 0; /// Assemble an array to the global lumped matrix array virtual void assembleToLumpedMatrix(const ID & dof_id, const Array<Real> & array_to_assemble, const ID & lumped_mtx, Real scale_factor = 1.) = 0; /** * Assemble elementary values to a local array of the size nb_nodes * * nb_dof_per_node. The dof number is implicitly considered as * conn(el, n) * nb_nodes_per_element + d. * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalArrayLocalArray( const Array<Real> & elementary_vect, Array<Real> & array_assembeled, const ElementType & type, const GhostType & ghost_type, Real scale_factor = 1., const Array<UInt> & filter_elements = empty_filter); /** * Assemble elementary values to the global residual array. The dof number is * implicitly considered as conn(el, n) * nb_nodes_per_element + d. * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalArrayToResidual( const ID & dof_id, const Array<Real> & elementary_vect, const ElementType & type, const GhostType & ghost_type, Real scale_factor = 1., const Array<UInt> & filter_elements = empty_filter); /** * Assemble elementary values to a global array corresponding to a lumped * matrix */ virtual void assembleElementalArrayToLumpedMatrix( const ID & dof_id, const Array<Real> & elementary_vect, const ID & lumped_mtx, const ElementType & type, const GhostType & ghost_type, Real scale_factor = 1., const Array<UInt> & filter_elements = empty_filter); /** * Assemble elementary values to the global residual array. The dof number is * implicitly considered as conn(el, n) * nb_nodes_per_element + d. With 0 < * n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat, const ElementType & type, const GhostType & ghost_type = _not_ghost, const MatrixType & elemental_matrix_type = _symmetric, const Array<UInt> & filter_elements = empty_filter) = 0; /// multiply a vector by a matrix and assemble the result to the residual virtual void assembleMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array<Real> & x, Real scale_factor = 1) = 0; /// multiply the dofs by a matrix and assemble the result to the residual virtual void assembleMatMulDOFsToResidual(const ID & A_id, Real scale_factor = 1); /// multiply a vector by a lumped matrix and assemble the result to the /// residual virtual void assembleLumpedMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array<Real> & x, Real scale_factor = 1) = 0; /// assemble coupling terms between to dofs virtual void assemblePreassembledMatrix(const ID & dof_id_m, const ID & dof_id_n, const ID & matrix_id, const TermsToAssemble & terms) = 0; /// sets the residual to 0 virtual void clearResidual() = 0; /// sets the matrix to 0 virtual void clearMatrix(const ID & mtx) = 0; /// sets the lumped matrix to 0 virtual void clearLumpedMatrix(const ID & mtx) = 0; /// splits the solution storage from a global view to the per dof storages void splitSolutionPerDOFs(); /// extract a lumped matrix part corresponding to a given dof virtual void getLumpedMatrixPerDOFs(const ID & dof_id, const ID & lumped_mtx, Array<Real> & lumped) = 0; protected: /// minimum functionality to implement per derived version of the DOFManager /// to allow the splitSolutionPerDOFs function to work virtual void getSolutionPerDOFs(const ID & dof_id, Array<Real> & solution_array) = 0; protected: /* ------------------------------------------------------------------------ */ /// register a matrix SparseMatrix & registerSparseMatrix(const ID & matrix_id, std::unique_ptr<SparseMatrix> & matrix); /// register a non linear solver instantiated by a derived class NonLinearSolver & registerNonLinearSolver(const ID & non_linear_solver_id, std::unique_ptr<NonLinearSolver> & non_linear_solver); /// register a time step solver instantiated by a derived class TimeStepSolver & registerTimeStepSolver(const ID & time_step_solver_id, std::unique_ptr<TimeStepSolver> & time_step_solver); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get the equation numbers corresponding to a dof_id. This might be used to /// access the matrix. inline const Array<UInt> & getEquationsNumbers(const ID & dof_id) const; /// Global number of dofs AKANTU_GET_MACRO(SystemSize, this->system_size, UInt); /// Local number of dofs AKANTU_GET_MACRO(LocalSystemSize, this->local_system_size, UInt); /// Retrieve all the registered DOFs std::vector<ID> getDOFIDs() const; /* ------------------------------------------------------------------------ */ /* DOFs and derivatives accessors */ /* ------------------------------------------------------------------------ */ /// Get a reference to the registered dof array for a given id inline Array<Real> & getDOFs(const ID & dofs_id); /// Get the support type of a given dof inline DOFSupportType getSupportType(const ID & dofs_id) const; /// are the dofs registered inline bool hasDOFs(const ID & dofs_id) const; /// Get a reference to the registered dof derivatives array for a given id inline Array<Real> & getDOFsDerivatives(const ID & dofs_id, UInt order); /// Does the dof has derivatives inline bool hasDOFsDerivatives(const ID & dofs_id, UInt order) const; /// Get a reference to the blocked dofs array registered for the given id inline const Array<bool> & getBlockedDOFs(const ID & dofs_id) const; /// Does the dof has a blocked array inline bool hasBlockedDOFs(const ID & dofs_id) const; /// Get a reference to the registered dof increment array for a given id inline Array<Real> & getDOFsIncrement(const ID & dofs_id); /// Does the dof has a increment array inline bool hasDOFsIncrement(const ID & dofs_id) const; /// Does the dof has a previous array inline Array<Real> & getPreviousDOFs(const ID & dofs_id); /// Get a reference to the registered dof array for previous step values a /// given id inline bool hasPreviousDOFs(const ID & dofs_id) const; /// saves the values from dofs to previous dofs virtual void savePreviousDOFs(const ID & dofs_id); /// Get a reference to the solution array registered for the given id inline const Array<Real> & getSolution(const ID & dofs_id) const; /* ------------------------------------------------------------------------ */ /* Matrices accessors */ /* ------------------------------------------------------------------------ */ /// Get an instance of a new SparseMatrix virtual SparseMatrix & getNewMatrix(const ID & matrix_id, const MatrixType & matrix_type) = 0; /// Get an instance of a new SparseMatrix as a copy of the SparseMatrix /// matrix_to_copy_id virtual SparseMatrix & getNewMatrix(const ID & matrix_id, const ID & matrix_to_copy_id) = 0; /// Get the reference of an existing matrix SparseMatrix & getMatrix(const ID & matrix_id); /// check if the given matrix exists bool hasMatrix(const ID & matrix_id) const; /// Get an instance of a new lumped matrix virtual Array<Real> & getNewLumpedMatrix(const ID & matrix_id); /// Get the lumped version of a given matrix const Array<Real> & getLumpedMatrix(const ID & matrix_id) const; /// Get the lumped version of a given matrix Array<Real> & getLumpedMatrix(const ID & matrix_id); /// check if the given matrix exists bool hasLumpedMatrix(const ID & matrix_id) const; /* ------------------------------------------------------------------------ */ /* Non linear system solver */ /* ------------------------------------------------------------------------ */ /// Get instance of a non linear solver virtual NonLinearSolver & getNewNonLinearSolver( const ID & nls_solver_id, const NonLinearSolverType & _non_linear_solver_type) = 0; /// get instance of a non linear solver virtual NonLinearSolver & getNonLinearSolver(const ID & nls_solver_id); /// check if the given solver exists bool hasNonLinearSolver(const ID & solver_id) const; /* ------------------------------------------------------------------------ */ /* Time-Step Solver */ /* ------------------------------------------------------------------------ */ /// Get instance of a time step solver virtual TimeStepSolver & getNewTimeStepSolver(const ID & time_step_solver_id, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver) = 0; /// get instance of a time step solver virtual TimeStepSolver & getTimeStepSolver(const ID & time_step_solver_id); /// check if the given solver exists bool hasTimeStepSolver(const ID & solver_id) const; /* ------------------------------------------------------------------------ */ const Mesh & getMesh() { if (mesh) { return *mesh; } else { AKANTU_EXCEPTION("No mesh registered in this dof manager"); } } /* ------------------------------------------------------------------------ */ AKANTU_GET_MACRO(Communicator, communicator, const auto &); AKANTU_GET_MACRO_NOT_CONST(Communicator, communicator, auto &); /* ------------------------------------------------------------------------ */ /* MeshEventHandler interface */ /* ------------------------------------------------------------------------ */ protected: /// helper function for the DOFManager::onNodesAdded method virtual std::pair<UInt, UInt> updateNodalDOFs(const ID & dof_id, const Array<UInt> & nodes_list); public: /// function to implement to react on akantu::NewNodesEvent void onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) override; /// function to implement to react on akantu::RemovedNodesEvent void onNodesRemoved(const Array<UInt> & nodes_list, const Array<UInt> & new_numbering, const RemovedNodesEvent & event) override; /// function to implement to react on akantu::NewElementsEvent void onElementsAdded(const Array<Element> & elements_list, const NewElementsEvent & event) override; /// function to implement to react on akantu::RemovedElementsEvent void onElementsRemoved(const Array<Element> & elements_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; /// function to implement to react on akantu::ChangedElementsEvent void onElementsChanged(const Array<Element> & old_elements_list, const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> & new_numbering, const ChangedElementsEvent & event) override; protected: struct DOFData; inline DOFData & getDOFData(const ID & dof_id); inline const DOFData & getDOFData(const ID & dof_id) const; template <class _DOFData> inline _DOFData & getDOFDataTyped(const ID & dof_id); template <class _DOFData> inline const _DOFData & getDOFDataTyped(const ID & dof_id) const; virtual DOFData & getNewDOFData(const ID & dof_id); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// dof representations in the dof manager struct DOFData { DOFData() = delete; explicit DOFData(const ID & dof_id); virtual ~DOFData(); /// DOF support type (nodal, general) this is needed to determine how the /// dof are shared among processors DOFSupportType support_type; ID group_support; /// Degree of freedom array Array<Real> * dof; /// Blocked degree of freedoms array Array<bool> * blocked_dofs; /// Degree of freedoms increment Array<Real> * increment; /// Degree of freedoms at previous step Array<Real> * previous; /// Solution associated to the dof Array<Real> solution; /// local numbering equation numbers Array<UInt> local_equation_number; /* ---------------------------------------------------------------------- */ /* data for dynamic simulations */ /* ---------------------------------------------------------------------- */ /// Degree of freedom derivatives arrays std::vector<Array<Real> *> dof_derivatives; }; /// type to store dofs information using DOFStorage = std::map<ID, std::unique_ptr<DOFData>>; /// type to store all the matrices using SparseMatricesMap = std::map<ID, std::unique_ptr<SparseMatrix>>; /// type to store all the lumped matrices using LumpedMatricesMap = std::map<ID, std::unique_ptr<Array<Real>>>; /// type to store all the non linear solver using NonLinearSolversMap = std::map<ID, std::unique_ptr<NonLinearSolver>>; /// type to store all the time step solver using TimeStepSolversMap = std::map<ID, std::unique_ptr<TimeStepSolver>>; /// store a reference to the dof arrays DOFStorage dofs; /// list of sparse matrices that where created SparseMatricesMap matrices; /// list of lumped matrices LumpedMatricesMap lumped_matrices; /// non linear solvers storage NonLinearSolversMap non_linear_solvers; /// time step solvers storage TimeStepSolversMap time_step_solvers; /// reference to the underlying mesh Mesh * mesh{nullptr}; /// Total number of degrees of freedom (size with the ghosts) UInt local_system_size{0}; /// Number of purely local dofs (size without the ghosts) UInt pure_local_system_size{0}; /// Total number of degrees of freedom UInt system_size{0}; /// Communicator used for this manager, should be the same as in the mesh if a /// mesh is registered Communicator & communicator; }; using DefaultDOFManagerFactory = Factory<DOFManager, ID, const ID &, const MemoryID &>; using DOFManagerFactory = Factory<DOFManager, ID, Mesh &, const ID &, const MemoryID &>; } // namespace akantu #include "dof_manager_inline_impl.cc" #endif /* __AKANTU_DOF_MANAGER_HH__ */ diff --git a/src/model/dof_manager_default.cc b/src/model/dof_manager_default.cc index c4b511c60..6e917a7d9 100644 --- a/src/model/dof_manager_default.cc +++ b/src/model/dof_manager_default.cc @@ -1,921 +1,922 @@ /** * @file dof_manager_default.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 11 16:21:01 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Thu Feb 08 2018 * * @brief Implementation of the default DOFManager * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager_default.hh" #include "communicator.hh" #include "dof_synchronizer.hh" #include "element_group.hh" #include "node_synchronizer.hh" #include "non_linear_solver_default.hh" #include "sparse_matrix_aij.hh" #include "terms_to_assemble.hh" #include "time_step_solver_default.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <memory> #include <numeric> #include <unordered_map> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ inline void DOFManagerDefault::addSymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & elementary_mat, const Vector<UInt> & equation_numbers, UInt max_size) { for (UInt i = 0; i < elementary_mat.rows(); ++i) { UInt c_irn = equation_numbers(i); if (c_irn < max_size) { for (UInt j = i; j < elementary_mat.cols(); ++j) { UInt c_jcn = equation_numbers(j); if (c_jcn < max_size) { matrix(c_irn, c_jcn) += elementary_mat(i, j); } } } } } /* -------------------------------------------------------------------------- */ inline void DOFManagerDefault::addUnsymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & elementary_mat, const Vector<UInt> & equation_numbers, UInt max_size) { for (UInt i = 0; i < elementary_mat.rows(); ++i) { UInt c_irn = equation_numbers(i); if (c_irn < max_size) { for (UInt j = 0; j < elementary_mat.cols(); ++j) { UInt c_jcn = equation_numbers(j); if (c_jcn < max_size) { if (c_jcn >= c_irn) { matrix(c_irn, c_jcn) += elementary_mat(i, j); } } } } } } /* -------------------------------------------------------------------------- */ inline void DOFManagerDefault::addElementalMatrixToUnsymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & elementary_mat, const Vector<UInt> & equation_numbers, UInt max_size) { for (UInt i = 0; i < elementary_mat.rows(); ++i) { UInt c_irn = equation_numbers(i); if (c_irn < max_size) { for (UInt j = 0; j < elementary_mat.cols(); ++j) { UInt c_jcn = equation_numbers(j); if (c_jcn < max_size) { matrix(c_irn, c_jcn) += elementary_mat(i, j); } } } } } /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFManagerDefault(const ID & id, const MemoryID & memory_id) : DOFManager(id, memory_id), residual(0, 1, std::string(id + ":residual")), global_residual(nullptr), global_solution(0, 1, std::string(id + ":global_solution")), global_blocked_dofs(0, 1, std::string(id + ":global_blocked_dofs")), previous_global_blocked_dofs( 0, 1, std::string(id + ":previous_global_blocked_dofs")), dofs_type(0, 1, std::string(id + ":dofs_type")), data_cache(0, 1, std::string(id + ":data_cache_array")), global_equation_number(0, 1, "global_equation_number"), synchronizer(nullptr) {} /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFManagerDefault(Mesh & mesh, const ID & id, const MemoryID & memory_id) : DOFManager(mesh, id, memory_id), residual(0, 1, std::string(id + ":residual")), global_residual(nullptr), global_solution(0, 1, std::string(id + ":global_solution")), global_blocked_dofs(0, 1, std::string(id + ":global_blocked_dofs")), previous_global_blocked_dofs( 0, 1, std::string(id + ":previous_global_blocked_dofs")), dofs_type(0, 1, std::string(id + ":dofs_type")), data_cache(0, 1, std::string(id + ":data_cache_array")), jacobian_release(0), global_equation_number(0, 1, "global_equation_number"), first_global_dof_id(0), synchronizer(nullptr) { if (this->mesh->isDistributed()) this->synchronizer = std::make_unique<DOFSynchronizer>( *this, this->id + ":dof_synchronizer", this->memory_id); } /* -------------------------------------------------------------------------- */ DOFManagerDefault::~DOFManagerDefault() = default; /* -------------------------------------------------------------------------- */ template <typename T> void DOFManagerDefault::assembleToGlobalArray( const ID & dof_id, const Array<T> & array_to_assemble, Array<T> & global_array, T scale_factor) { AKANTU_DEBUG_IN(); const Array<UInt> & equation_number = this->getLocalEquationNumbers(dof_id); UInt nb_degree_of_freedoms = array_to_assemble.size() * array_to_assemble.getNbComponent(); AKANTU_DEBUG_ASSERT(equation_number.size() == nb_degree_of_freedoms, "The array to assemble does not have a correct size." << " (" << array_to_assemble.getID() << ")"); typename Array<T>::const_scalar_iterator arr_it = array_to_assemble.begin_reinterpret(nb_degree_of_freedoms); Array<UInt>::const_scalar_iterator equ_it = equation_number.begin(); for (UInt d = 0; d < nb_degree_of_freedoms; ++d, ++arr_it, ++equ_it) { global_array(*equ_it) += scale_factor * (*arr_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFDataDefault::DOFDataDefault(const ID & dof_id) : DOFData(dof_id), associated_nodes(0, 1, dof_id + "associated_nodes") {} /* -------------------------------------------------------------------------- */ DOFManager::DOFData & DOFManagerDefault::getNewDOFData(const ID & dof_id) { this->dofs[dof_id] = std::make_unique<DOFDataDefault>(dof_id); return *this->dofs[dof_id]; } /* -------------------------------------------------------------------------- */ class GlobalDOFInfoDataAccessor : public DataAccessor<UInt> { public: using size_type = typename std::unordered_map<UInt, std::vector<UInt>>::size_type; GlobalDOFInfoDataAccessor() = default; void addDOFToNode(UInt node, UInt dof) { dofs_per_node[node].push_back(dof); } UInt getNthDOFForNode(UInt nth_dof, UInt node) const { auto it = dofs_per_node.find(node); AKANTU_DEBUG_ASSERT(it != dofs_per_node.end(), "Did not find the node " << node); return it->second[nth_dof]; } UInt getNbData(const Array<UInt> & nodes, const SynchronizationTag & tag) const override { if (tag == _gst_size) { return nodes.size() * sizeof(size_type); } if (tag == _gst_update) { UInt total_size = 0; for (auto node : nodes) { auto it = dofs_per_node.find(node); if (it != dofs_per_node.end()) total_size += CommunicationBuffer::sizeInBuffer(it->second); } return total_size; } return 0; } void packData(CommunicationBuffer & buffer, const Array<UInt> & nodes, const SynchronizationTag & tag) const override { for (auto node : nodes) { auto it = dofs_per_node.find(node); if (tag == _gst_size) { if (it != dofs_per_node.end()) { buffer << it->second.size(); } else { buffer << 0; } } else if (tag == _gst_update) { if (it != dofs_per_node.end()) buffer << it->second; } } } void unpackData(CommunicationBuffer & buffer, const Array<UInt> & nodes, const SynchronizationTag & tag) override { for (auto node : nodes) { auto it = dofs_per_node.find(node); if (tag == _gst_size) { size_type size; buffer >> size; if (size != 0) dofs_per_node[node].resize(size); } else if (tag == _gst_update) { if (it != dofs_per_node.end()) buffer >> it->second; } } } protected: std::unordered_map<UInt, std::vector<UInt>> dofs_per_node; }; /* -------------------------------------------------------------------------- */ void DOFManagerDefault::registerDOFsInternal(const ID & dof_id, UInt nb_dofs, UInt nb_pure_local_dofs) { // auto prank = this->communicator.whoAmI(); // auto psize = this->communicator.getNbProc(); // access the relevant data to update auto & dof_data = this->getDOFDataTyped<DOFDataDefault>(dof_id); const auto & support_type = dof_data.support_type; const auto & group = dof_data.group_support; if (support_type == _dst_nodal and group != "__mesh__") { auto & support_nodes = this->mesh->getElementGroup(group).getNodeGroup().getNodes(); this->updateDOFsData( dof_data, nb_dofs, nb_pure_local_dofs, [&support_nodes](UInt node) -> UInt { return support_nodes[node]; }); } else { this->updateDOFsData(dof_data, nb_dofs, nb_pure_local_dofs, [](UInt node) -> UInt { return node; }); } // update the synchronizer if needed if (this->synchronizer) this->synchronizer->registerDOFs(dof_id); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const DOFSupportType & support_type) { // stores the current numbers of dofs UInt nb_dofs_old = this->local_system_size; UInt nb_pure_local_dofs_old = this->pure_local_system_size; // update or create the dof_data DOFManager::registerDOFs(dof_id, dofs_array, support_type); UInt nb_dofs = this->local_system_size - nb_dofs_old; UInt nb_pure_local_dofs = this->pure_local_system_size - nb_pure_local_dofs_old; this->registerDOFsInternal(dof_id, nb_dofs, nb_pure_local_dofs); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const ID & group_support) { // stores the current numbers of dofs UInt nb_dofs_old = this->local_system_size; UInt nb_pure_local_dofs_old = this->pure_local_system_size; // update or create the dof_data DOFManager::registerDOFs(dof_id, dofs_array, group_support); UInt nb_dofs = this->local_system_size - nb_dofs_old; UInt nb_pure_local_dofs = this->pure_local_system_size - nb_pure_local_dofs_old; this->registerDOFsInternal(dof_id, nb_dofs, nb_pure_local_dofs); } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManagerDefault::getNewMatrix(const ID & id, const MatrixType & matrix_type) { ID matrix_id = this->id + ":mtx:" + id; std::unique_ptr<SparseMatrix> sm = std::make_unique<SparseMatrixAIJ>(*this, matrix_type, matrix_id); return this->registerSparseMatrix(matrix_id, sm); } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManagerDefault::getNewMatrix(const ID & id, const ID & matrix_to_copy_id) { ID matrix_id = this->id + ":mtx:" + id; SparseMatrixAIJ & sm_to_copy = this->getMatrix(matrix_to_copy_id); std::unique_ptr<SparseMatrix> sm = std::make_unique<SparseMatrixAIJ>(sm_to_copy, matrix_id); return this->registerSparseMatrix(matrix_id, sm); } /* -------------------------------------------------------------------------- */ SparseMatrixAIJ & DOFManagerDefault::getMatrix(const ID & id) { SparseMatrix & matrix = DOFManager::getMatrix(id); return dynamic_cast<SparseMatrixAIJ &>(matrix); } /* -------------------------------------------------------------------------- */ NonLinearSolver & DOFManagerDefault::getNewNonLinearSolver(const ID & id, const NonLinearSolverType & type) { ID non_linear_solver_id = this->id + ":nls:" + id; std::unique_ptr<NonLinearSolver> nls; switch (type) { #if defined(AKANTU_IMPLICIT) case _nls_newton_raphson: case _nls_newton_raphson_modified: { nls = std::make_unique<NonLinearSolverNewtonRaphson>( *this, type, non_linear_solver_id, this->memory_id); break; } case _nls_linear: { nls = std::make_unique<NonLinearSolverLinear>( *this, type, non_linear_solver_id, this->memory_id); break; } #endif case _nls_lumped: { nls = std::make_unique<NonLinearSolverLumped>( *this, type, non_linear_solver_id, this->memory_id); break; } default: AKANTU_EXCEPTION("The asked type of non linear solver is not supported by " "this dof manager"); } return this->registerNonLinearSolver(non_linear_solver_id, nls); } /* -------------------------------------------------------------------------- */ TimeStepSolver & DOFManagerDefault::getNewTimeStepSolver(const ID & id, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver) { ID time_step_solver_id = this->id + ":tss:" + id; std::unique_ptr<TimeStepSolver> tss = std::make_unique<TimeStepSolverDefault>( *this, type, non_linear_solver, time_step_solver_id, this->memory_id); return this->registerTimeStepSolver(time_step_solver_id, tss); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::clearResidual() { this->residual.resize(this->local_system_size); this->residual.clear(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::clearMatrix(const ID & mtx) { this->getMatrix(mtx).clear(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::clearLumpedMatrix(const ID & mtx) { this->getLumpedMatrix(mtx).clear(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::updateGlobalBlockedDofs() { auto it = this->dofs.begin(); auto end = this->dofs.end(); this->previous_global_blocked_dofs.copy(this->global_blocked_dofs); this->global_blocked_dofs.resize(this->local_system_size); this->global_blocked_dofs.clear(); for (; it != end; ++it) { if (!this->hasBlockedDOFs(it->first)) continue; DOFData & dof_data = *it->second; this->assembleToGlobalArray(it->first, *dof_data.blocked_dofs, this->global_blocked_dofs, true); } } /* -------------------------------------------------------------------------- */ template <typename T> void DOFManagerDefault::getArrayPerDOFs(const ID & dof_id, const Array<T> & global_array, Array<T> & local_array) const { AKANTU_DEBUG_IN(); const Array<UInt> & equation_number = this->getLocalEquationNumbers(dof_id); UInt nb_degree_of_freedoms = equation_number.size(); local_array.resize(nb_degree_of_freedoms / local_array.getNbComponent()); auto loc_it = local_array.begin_reinterpret(nb_degree_of_freedoms); auto equ_it = equation_number.begin(); for (UInt d = 0; d < nb_degree_of_freedoms; ++d, ++loc_it, ++equ_it) { (*loc_it) = global_array(*equ_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ // void DOFManagerDefault::getEquationsNumbers(const ID & dof_id, // Array<UInt> & equation_numbers) { // AKANTU_DEBUG_IN(); // this->getArrayPerDOFs(dof_id, this->global_equation_number, // equation_numbers); AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::getSolutionPerDOFs(const ID & dof_id, Array<Real> & solution_array) { AKANTU_DEBUG_IN(); this->getArrayPerDOFs(dof_id, this->global_solution, solution_array); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::getLumpedMatrixPerDOFs(const ID & dof_id, const ID & lumped_mtx, Array<Real> & lumped) { AKANTU_DEBUG_IN(); this->getArrayPerDOFs(dof_id, this->getLumpedMatrix(lumped_mtx), lumped); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleToResidual( const ID & dof_id, const Array<Real> & array_to_assemble, Real scale_factor) { AKANTU_DEBUG_IN(); this->assembleToGlobalArray(dof_id, array_to_assemble, this->residual, scale_factor); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleToLumpedMatrix( const ID & dof_id, const Array<Real> & array_to_assemble, const ID & lumped_mtx, Real scale_factor) { AKANTU_DEBUG_IN(); Array<Real> & lumped = this->getLumpedMatrix(lumped_mtx); this->assembleToGlobalArray(dof_id, array_to_assemble, lumped, scale_factor); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array<Real> & x, Real scale_factor) { SparseMatrixAIJ & A = this->getMatrix(A_id); // Array<Real> data_cache(this->local_system_size, 1, 0.); this->data_cache.resize(this->local_system_size); this->data_cache.clear(); this->assembleToGlobalArray(dof_id, x, data_cache, 1.); A.matVecMul(data_cache, this->residual, scale_factor, 1.); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleLumpedMatMulVectToResidual( const ID & dof_id, const ID & A_id, const Array<Real> & x, Real scale_factor) { const Array<Real> & A = this->getLumpedMatrix(A_id); // Array<Real> data_cache(this->local_system_size, 1, 0.); this->data_cache.resize(this->local_system_size); this->data_cache.clear(); this->assembleToGlobalArray(dof_id, x, data_cache, scale_factor); auto A_it = A.begin(); auto A_end = A.end(); auto x_it = data_cache.begin(); auto r_it = this->residual.begin(); for (; A_it != A_end; ++A_it, ++x_it, ++r_it) { *r_it += *A_it * *x_it; } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat, const ElementType & type, const GhostType & ghost_type, const MatrixType & elemental_matrix_type, const Array<UInt> & filter_elements) { AKANTU_DEBUG_IN(); DOFData & dof_data = this->getDOFData(dof_id); AKANTU_DEBUG_ASSERT(dof_data.support_type == _dst_nodal, "This function applies only on Nodal dofs"); this->addToProfile(matrix_id, dof_id, type, ghost_type); const Array<UInt> & equation_number = this->getLocalEquationNumbers(dof_id); SparseMatrixAIJ & A = this->getMatrix(matrix_id); UInt nb_element; UInt * filter_it = nullptr; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); filter_it = filter_elements.storage(); } else { if (dof_data.group_support != "__mesh__") { const Array<UInt> & group_elements = this->mesh->getElementGroup(dof_data.group_support) .getElements(type, ghost_type); nb_element = group_elements.size(); filter_it = group_elements.storage(); } else { nb_element = this->mesh->getNbElement(type, ghost_type); } } AKANTU_DEBUG_ASSERT(elementary_mat.size() == nb_element, "The vector elementary_mat(" << elementary_mat.getID() << ") has not the good size."); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = dof_data.dof->getNbComponent(); const Array<UInt> & connectivity = this->mesh->getConnectivity(type, ghost_type); auto conn_begin = connectivity.begin(nb_nodes_per_element); auto conn_it = conn_begin; UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom; Vector<UInt> element_eq_nb(nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_matrix_iterator el_mat_it = elementary_mat.begin(size_mat, size_mat); for (UInt e = 0; e < nb_element; ++e, ++el_mat_it) { if (filter_it) conn_it = conn_begin + *filter_it; this->extractElementEquationNumber(equation_number, *conn_it, nb_degree_of_freedom, element_eq_nb); std::transform(element_eq_nb.storage(), element_eq_nb.storage() + element_eq_nb.size(), element_eq_nb.storage(), [&](UInt & local) -> UInt { return this->localToGlobalEquationNumber(local); }); if (filter_it) ++filter_it; else ++conn_it; if (A.getMatrixType() == _symmetric) if (elemental_matrix_type == _symmetric) this->addSymmetricElementalMatrixToSymmetric(A, *el_mat_it, element_eq_nb, A.size()); else this->addUnsymmetricElementalMatrixToSymmetric(A, *el_mat_it, element_eq_nb, A.size()); else this->addElementalMatrixToUnsymmetric(A, *el_mat_it, element_eq_nb, A.size()); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assemblePreassembledMatrix( const ID & dof_id_m, const ID & dof_id_n, const ID & matrix_id, const TermsToAssemble & terms) { const Array<UInt> & equation_number_m = this->getLocalEquationNumbers(dof_id_m); const Array<UInt> & equation_number_n = this->getLocalEquationNumbers(dof_id_n); SparseMatrixAIJ & A = this->getMatrix(matrix_id); for (const auto & term : terms) { UInt gi = this->localToGlobalEquationNumber(equation_number_m(term.i())); UInt gj = this->localToGlobalEquationNumber(equation_number_n(term.j())); A.add(gi, gj, term); } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const DOFData & dof_data = this->getDOFData(dof_id); if (dof_data.support_type != _dst_nodal) return; auto mat_dof = std::make_pair(matrix_id, dof_id); auto type_pair = std::make_pair(type, ghost_type); auto prof_it = this->matrix_profiled_dofs.find(mat_dof); if (prof_it != this->matrix_profiled_dofs.end() && std::find(prof_it->second.begin(), prof_it->second.end(), type_pair) != prof_it->second.end()) return; UInt nb_degree_of_freedom_per_node = dof_data.dof->getNbComponent(); const Array<UInt> & equation_number = this->getLocalEquationNumbers(dof_id); SparseMatrixAIJ & A = this->getMatrix(matrix_id); UInt size = A.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto & connectivity = this->mesh->getConnectivity(type, ghost_type); auto cbegin = connectivity.begin(nb_nodes_per_element); auto cit = cbegin; UInt nb_elements = connectivity.size(); UInt * ge_it = nullptr; if (dof_data.group_support != "__mesh__") { const Array<UInt> & group_elements = this->mesh->getElementGroup(dof_data.group_support) .getElements(type, ghost_type); ge_it = group_elements.storage(); nb_elements = group_elements.size(); } UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom_per_node; Vector<UInt> element_eq_nb(size_mat); for (UInt e = 0; e < nb_elements; ++e) { if (ge_it) cit = cbegin + *ge_it; this->extractElementEquationNumber( equation_number, *cit, nb_degree_of_freedom_per_node, element_eq_nb); std::transform(element_eq_nb.storage(), element_eq_nb.storage() + element_eq_nb.size(), element_eq_nb.storage(), [&](UInt & local) -> UInt { return this->localToGlobalEquationNumber(local); }); if (ge_it) ++ge_it; else ++cit; for (UInt i = 0; i < size_mat; ++i) { UInt c_irn = element_eq_nb(i); if (c_irn < size) { for (UInt j = 0; j < size_mat; ++j) { UInt c_jcn = element_eq_nb(j); if (c_jcn < size) { A.add(c_irn, c_jcn); } } } } } this->matrix_profiled_dofs[mat_dof].push_back(type_pair); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::applyBoundary(const ID & matrix_id) { SparseMatrixAIJ & J = this->getMatrix(matrix_id); if (this->jacobian_release == J.getValueRelease()) { auto are_equal = std::equal(global_blocked_dofs.begin(), global_blocked_dofs.end(), previous_global_blocked_dofs.begin()); if (not are_equal) J.applyBoundary(); previous_global_blocked_dofs.copy(global_blocked_dofs); } else { J.applyBoundary(); } this->jacobian_release = J.getValueRelease(); } /* -------------------------------------------------------------------------- */ const Array<Real> & DOFManagerDefault::getGlobalResidual() { if (this->synchronizer) { if (not this->global_residual) { this->global_residual = std::make_unique<Array<Real>>(0, 1, "global_residual"); } if (this->synchronizer->getCommunicator().whoAmI() == 0) { this->global_residual->resize(this->system_size); this->synchronizer->gather(this->residual, *this->global_residual); } else { this->synchronizer->gather(this->residual); } return *this->global_residual; } else { return this->residual; } } /* -------------------------------------------------------------------------- */ const Array<Real> & DOFManagerDefault::getResidual() const { return this->residual; } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::setGlobalSolution(const Array<Real> & solution) { if (this->synchronizer) { if (this->synchronizer->getCommunicator().whoAmI() == 0) { this->synchronizer->scatter(this->global_solution, solution); } else { this->synchronizer->scatter(this->global_solution); } } else { AKANTU_DEBUG_ASSERT(solution.size() == this->global_solution.size(), "Sequential call to this function needs the solution " "to be the same size as the global_solution"); this->global_solution.copy(solution); } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) { DOFManager::onNodesAdded(nodes_list, event); if (this->synchronizer) this->synchronizer->onNodesAdded(nodes_list); } /* -------------------------------------------------------------------------- */ std::pair<UInt, UInt> DOFManagerDefault::updateNodalDOFs(const ID & dof_id, const Array<UInt> & nodes_list) { UInt nb_new_local_dofs, nb_new_pure_local; std::tie(nb_new_local_dofs, nb_new_pure_local) = DOFManager::updateNodalDOFs(dof_id, nodes_list); auto & dof_data = this->getDOFDataTyped<DOFDataDefault>(dof_id); updateDOFsData(dof_data, nb_new_local_dofs, nb_new_pure_local, [&nodes_list](UInt pos) -> UInt { return nodes_list[pos]; }); return std::make_pair(nb_new_local_dofs, nb_new_pure_local); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::updateDOFsData( DOFDataDefault & dof_data, UInt nb_new_local_dofs, UInt nb_new_pure_local, const std::function<UInt(UInt)> & getNode) { auto prank = this->communicator.whoAmI(); auto psize = this->communicator.getNbProc(); // access the relevant data to update const auto & support_type = dof_data.support_type; GlobalDOFInfoDataAccessor data_accessor; // resize all relevant arrays this->residual.resize(this->local_system_size); this->dofs_type.resize(this->local_system_size); this->global_solution.resize(this->local_system_size); this->global_blocked_dofs.resize(this->local_system_size); this->previous_global_blocked_dofs.resize(this->local_system_size); this->global_equation_number.resize(this->local_system_size); for (auto & lumped_matrix : lumped_matrices) lumped_matrix.second->resize(this->local_system_size); dof_data.local_equation_number.reserve(dof_data.local_equation_number.size() + nb_new_local_dofs); // determine the first local/global dof id to use Array<UInt> nb_dofs_per_proc(psize); nb_dofs_per_proc(prank) = nb_new_pure_local; this->communicator.allGather(nb_dofs_per_proc); this->first_global_dof_id += std::accumulate( nb_dofs_per_proc.begin(), nb_dofs_per_proc.begin() + prank, 0); UInt first_dof_id = this->local_system_size - nb_new_local_dofs; if (support_type == _dst_nodal) { dof_data.associated_nodes.reserve(dof_data.associated_nodes.size() + nb_new_local_dofs); } // update per dof info for (UInt d = 0; d < nb_new_local_dofs; ++d) { UInt local_eq_num = first_dof_id + d; dof_data.local_equation_number.push_back(local_eq_num); bool is_local_dof = true; // determine the dof type switch (support_type) { case _dst_nodal: { UInt node = getNode(d / dof_data.dof->getNbComponent()); this->dofs_type(local_eq_num) = this->mesh->getNodeType(node); dof_data.associated_nodes.push_back(node); is_local_dof = this->mesh->isLocalOrMasterNode(node); if (is_local_dof) { data_accessor.addDOFToNode(node, first_global_dof_id); } break; } case _dst_generic: { this->dofs_type(local_eq_num) = _nt_normal; break; } default: { AKANTU_EXCEPTION("This type of dofs is not handled yet."); } } // update global id for local dofs if (is_local_dof) { this->global_equation_number(local_eq_num) = this->first_global_dof_id; this->global_to_local_mapping[this->first_global_dof_id] = local_eq_num; ++this->first_global_dof_id; } else { this->global_equation_number(local_eq_num) = 0; } } // synchronize the global numbering for slaves if (support_type == _dst_nodal && this->synchronizer) { auto nb_dofs_per_node = dof_data.dof->getNbComponent(); auto & node_synchronizer = this->mesh->getNodeSynchronizer(); node_synchronizer.synchronizeOnce(data_accessor, _gst_size); node_synchronizer.synchronizeOnce(data_accessor, _gst_update); std::vector<UInt> counters(nb_new_local_dofs / nb_dofs_per_node); for (UInt d = 0; d < nb_new_local_dofs; ++d) { UInt local_eq_num = first_dof_id + d; if (not this->isSlaveDOF(local_eq_num)) continue; UInt node = d / nb_dofs_per_node; UInt dof_count = counters[node]++; node = getNode(node); UInt global_dof_id = data_accessor.getNthDOFForNode(dof_count, node); this->global_equation_number(local_eq_num) = global_dof_id; this->global_to_local_mapping[global_dof_id] = local_eq_num; } } } /* -------------------------------------------------------------------------- */ // register in factory static bool default_dof_manager_is_registered[[gnu::unused]] = DefaultDOFManagerFactory::getInstance().registerAllocator( "default", [](const ID & id, const MemoryID & mem_id) -> std::unique_ptr<DOFManager> { return std::make_unique<DOFManagerDefault>(id, mem_id); }); static bool dof_manager_is_registered[[gnu::unused]] = DOFManagerFactory::getInstance().registerAllocator( "default", [](Mesh & mesh, const ID & id, const MemoryID & mem_id) -> std::unique_ptr<DOFManager> { return std::make_unique<DOFManagerDefault>(mesh, id, mem_id); }); } // namespace akantu diff --git a/src/model/dof_manager_default.hh b/src/model/dof_manager_default.hh index 8acd160f9..e8efa3b50 100644 --- a/src/model/dof_manager_default.hh +++ b/src/model/dof_manager_default.hh @@ -1,360 +1,361 @@ /** * @file dof_manager_default.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 11 14:06:18 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Default implementation of the dof manager * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager.hh" /* -------------------------------------------------------------------------- */ #include <functional> #include <unordered_map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DOF_MANAGER_DEFAULT_HH__ #define __AKANTU_DOF_MANAGER_DEFAULT_HH__ namespace akantu { class SparseMatrixAIJ; class NonLinearSolverDefault; class TimeStepSolverDefault; class DOFSynchronizer; } // namespace akantu namespace akantu { class DOFManagerDefault : public DOFManager { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DOFManagerDefault(const ID & id = "dof_manager_default", const MemoryID & memory_id = 0); DOFManagerDefault(Mesh & mesh, const ID & id = "dof_manager_default", const MemoryID & memory_id = 0); ~DOFManagerDefault() override; protected: struct DOFDataDefault : public DOFData { explicit DOFDataDefault(const ID & dof_id); /// associated node for _dst_nodal dofs only Array<UInt> associated_nodes; }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ private: void registerDOFsInternal(const ID & dof_id, UInt nb_dofs, UInt nb_pure_local_dofs); public: /// register an array of degree of freedom void registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const DOFSupportType & support_type) override; /// the dof as an implied type of _dst_nodal and is defined only on a subset /// of nodes void registerDOFs(const ID & dof_id, Array<Real> & dofs_array, const ID & group_support) override; /// Assemble an array to the global residual array void assembleToResidual(const ID & dof_id, const Array<Real> & array_to_assemble, Real scale_factor = 1.) override; /// Assemble an array to the global lumped matrix array void assembleToLumpedMatrix(const ID & dof_id, const Array<Real> & array_to_assemble, const ID & lumped_mtx, Real scale_factor = 1.) override; /** * Assemble elementary values to the global matrix. The dof number is * implicitly considered as conn(el, n) * nb_nodes_per_element + d. * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ void assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat, const ElementType & type, const GhostType & ghost_type, const MatrixType & elemental_matrix_type, const Array<UInt> & filter_elements) override; /// multiply a vector by a matrix and assemble the result to the residual void assembleMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array<Real> & x, Real scale_factor = 1) override; /// multiply a vector by a lumped matrix and assemble the result to the /// residual void assembleLumpedMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array<Real> & x, Real scale_factor = 1) override; /// assemble coupling terms between to dofs void assemblePreassembledMatrix(const ID & dof_id_m, const ID & dof_id_n, const ID & matrix_id, const TermsToAssemble & terms) override; protected: /// Assemble an array to the global residual array template <typename T> void assembleToGlobalArray(const ID & dof_id, const Array<T> & array_to_assemble, Array<T> & global_array, T scale_factor); public: /// clear the residual void clearResidual() override; /// sets the matrix to 0 void clearMatrix(const ID & mtx) override; /// sets the lumped matrix to 0 void clearLumpedMatrix(const ID & mtx) override; /// update the global dofs vector virtual void updateGlobalBlockedDofs(); /// apply boundary conditions to jacobian matrix virtual void applyBoundary(const ID & matrix_id = "J"); // void getEquationsNumbers(const ID & dof_id, // Array<UInt> & equation_numbers) override; protected: /// Get local part of an array corresponding to a given dofdata template <typename T> void getArrayPerDOFs(const ID & dof_id, const Array<T> & global_array, Array<T> & local_array) const; /// Get the part of the solution corresponding to the dof_id void getSolutionPerDOFs(const ID & dof_id, Array<Real> & solution_array) override; /// fill a Vector with the equation numbers corresponding to the given /// connectivity inline void extractElementEquationNumber( const Array<UInt> & equation_numbers, const Vector<UInt> & connectivity, UInt nb_degree_of_freedom, Vector<UInt> & local_equation_number); public: /// extract a lumped matrix part corresponding to a given dof void getLumpedMatrixPerDOFs(const ID & dof_id, const ID & lumped_mtx, Array<Real> & lumped) override; private: /// Add a symmetric matrices to a symmetric sparse matrix void addSymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & element_mat, const Vector<UInt> & equation_numbers, UInt max_size); /// Add a unsymmetric matrices to a symmetric sparse matrix (i.e. cohesive /// elements) void addUnsymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & element_mat, const Vector<UInt> & equation_numbers, UInt max_size); /// Add a matrices to a unsymmetric sparse matrix void addElementalMatrixToUnsymmetric(SparseMatrixAIJ & matrix, const Matrix<Real> & element_mat, const Vector<UInt> & equation_numbers, UInt max_size); void addToProfile(const ID & matrix_id, const ID & dof_id, const ElementType & type, const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* MeshEventHandler interface */ /* ------------------------------------------------------------------------ */ protected: std::pair<UInt, UInt> updateNodalDOFs(const ID & dof_id, const Array<UInt> & nodes_list) override; private: void updateDOFsData(DOFDataDefault & dof_data, UInt nb_new_local_dofs, UInt nb_new_pure_local, const std::function<UInt(UInt)> & getNode); public: /// function to implement to react on akantu::NewNodesEvent void onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get an instance of a new SparseMatrix SparseMatrix & getNewMatrix(const ID & matrix_id, const MatrixType & matrix_type) override; /// Get an instance of a new SparseMatrix as a copy of the SparseMatrix /// matrix_to_copy_id SparseMatrix & getNewMatrix(const ID & matrix_id, const ID & matrix_to_copy_id) override; /// Get the reference of an existing matrix SparseMatrixAIJ & getMatrix(const ID & matrix_id); /* ------------------------------------------------------------------------ */ /* Non Linear Solver */ /* ------------------------------------------------------------------------ */ /// Get instance of a non linear solver NonLinearSolver & getNewNonLinearSolver( const ID & nls_solver_id, const NonLinearSolverType & _non_linear_solver_type) override; /* ------------------------------------------------------------------------ */ /* Time-Step Solver */ /* ------------------------------------------------------------------------ */ /// Get instance of a time step solver TimeStepSolver & getNewTimeStepSolver(const ID & id, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver) override; /* ------------------------------------------------------------------------ */ /// Get the solution array AKANTU_GET_MACRO_NOT_CONST(GlobalSolution, global_solution, Array<Real> &); /// Set the global solution array void setGlobalSolution(const Array<Real> & solution); /// Get the global residual array across processors (SMP call) const Array<Real> & getGlobalResidual(); /// Get the residual array const Array<Real> & getResidual() const; /// Get the blocked dofs array AKANTU_GET_MACRO(GlobalBlockedDOFs, global_blocked_dofs, const Array<bool> &); /// Get the blocked dofs array AKANTU_GET_MACRO(PreviousGlobalBlockedDOFs, previous_global_blocked_dofs, const Array<bool> &); /// Get the location type of a given dof inline bool isLocalOrMasterDOF(UInt local_dof_num); /// Answer to the question is a dof a slave dof ? inline bool isSlaveDOF(UInt local_dof_num); /// get the equation numbers (in local numbering) corresponding to a dof ID inline const Array<UInt> & getLocalEquationNumbers(const ID & dof_id) const; /// tells if the dof manager knows about a global dof bool hasGlobalEquationNumber(UInt global) const; /// return the local index of the global equation number inline UInt globalToLocalEquationNumber(UInt global) const; /// converts local equation numbers to global equation numbers; inline UInt localToGlobalEquationNumber(UInt local) const; /// get the array of dof types (use only if you know what you do...) inline Int getDOFType(UInt local_id) const; /// get the array of dof types (use only if you know what you do...) inline const Array<UInt> & getDOFsAssociatedNodes(const ID & dof_id) const; /// access the internal dof_synchronizer AKANTU_GET_MACRO_NOT_CONST(Synchronizer, *synchronizer, DOFSynchronizer &); /// access the internal dof_synchronizer bool hasSynchronizer() const { return synchronizer != nullptr; } protected: DOFData & getNewDOFData(const ID & dof_id) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: // using AIJMatrixMap = std::map<ID, std::unique_ptr<SparseMatrixAIJ>>; // using DefaultNonLinearSolversMap = // std::map<ID, std::unique_ptr<NonLinearSolverDefault>>; // using DefaultTimeStepSolversMap = // std::map<ID, std::unique_ptr<TimeStepSolverDefault>>; using DOFToMatrixProfile = std::map<std::pair<ID, ID>, std::vector<std::pair<ElementType, GhostType>>>; /// contains the the dofs that where added to the profile of a given matrix. DOFToMatrixProfile matrix_profiled_dofs; /// rhs to the system of equation corresponding to the residual linked to the /// different dofs Array<Real> residual; /// rhs used only on root proc in case of parallel computing, this is the full /// gathered rhs array std::unique_ptr<Array<Real>> global_residual; /// solution of the system of equation corresponding to the different dofs Array<Real> global_solution; /// blocked degree of freedom in the system equation corresponding to the /// different dofs Array<bool> global_blocked_dofs; /// blocked degree of freedom in the system equation corresponding to the /// different dofs Array<bool> previous_global_blocked_dofs; /// define the dofs type, local, shared, ghost Array<Int> dofs_type; /// Map of the different matrices stored in the dof manager // AIJMatrixMap aij_matrices; /// Map of the different time step solvers stored with there real type // DefaultTimeStepSolversMap default_time_step_solver_map; /// Memory cache, this is an array to keep the temporary memory needed for /// some operations, it is meant to be resized or cleared when needed Array<Real> data_cache; /// Release at last apply boundary on jacobian UInt jacobian_release{0}; /// equation number in global numbering Array<UInt> global_equation_number; using equation_numbers_map = std::unordered_map<UInt, UInt>; /// dual information of global_equation_number equation_numbers_map global_to_local_mapping; /// accumulator to know what would be the next global id to use UInt first_global_dof_id{0}; /// synchronizer to maintain coherency in dof fields std::unique_ptr<DOFSynchronizer> synchronizer; }; } // namespace akantu #include "dof_manager_default_inline_impl.cc" #endif /* __AKANTU_DOF_MANAGER_DEFAULT_HH__ */ diff --git a/src/model/dof_manager_default_inline_impl.cc b/src/model/dof_manager_default_inline_impl.cc index 1dc37020f..26b764a7c 100644 --- a/src/model/dof_manager_default_inline_impl.cc +++ b/src/model/dof_manager_default_inline_impl.cc @@ -1,104 +1,105 @@ /** * @file dof_manager_default_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 12 10:57:47 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of the DOFManagerDefault inline functions * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager_default.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_CC__ #define __AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline bool DOFManagerDefault::isLocalOrMasterDOF(UInt dof_num) { Int dof_type = this->dofs_type(dof_num); return (dof_type == Int(_nt_normal)) || (dof_type == Int(_nt_master)); } /* -------------------------------------------------------------------------- */ inline bool DOFManagerDefault::isSlaveDOF(UInt dof_num) { Int dof_type = this->dofs_type(dof_num); return (dof_type >= 0); } /* -------------------------------------------------------------------------- */ inline const Array<UInt> & DOFManagerDefault::getLocalEquationNumbers(const ID & dof_id) const { return this->getDOFData(dof_id).local_equation_number; } inline const Array<UInt> & DOFManagerDefault::getDOFsAssociatedNodes(const ID & dof_id) const { const auto & dof_data = this->getDOFDataTyped<DOFDataDefault>(dof_id); return dof_data.associated_nodes; } /* -------------------------------------------------------------------------- */ inline void DOFManagerDefault::extractElementEquationNumber( const Array<UInt> & equation_numbers, const Vector<UInt> & connectivity, UInt nb_degree_of_freedom, Vector<UInt> & element_equation_number) { for (UInt i = 0, ld = 0; i < connectivity.size(); ++i) { UInt n = connectivity(i); for (UInt d = 0; d < nb_degree_of_freedom; ++d, ++ld) { element_equation_number(ld) = equation_numbers(n * nb_degree_of_freedom + d); } } } /* -------------------------------------------------------------------------- */ inline UInt DOFManagerDefault::localToGlobalEquationNumber(UInt local) const { return this->global_equation_number(local); } /* -------------------------------------------------------------------------- */ inline bool DOFManagerDefault::hasGlobalEquationNumber(UInt global) const { auto it = this->global_to_local_mapping.find(global); return (it != this->global_to_local_mapping.end()); } /* -------------------------------------------------------------------------- */ inline UInt DOFManagerDefault::globalToLocalEquationNumber(UInt global) const { auto it = this->global_to_local_mapping.find(global); AKANTU_DEBUG_ASSERT(it != this->global_to_local_mapping.end(), "This global equation number " << global << " does not exists in " << this->id); return it->second; } /* -------------------------------------------------------------------------- */ inline Int DOFManagerDefault::getDOFType(UInt local_id) const { return this->dofs_type(local_id); } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_CC_ */ diff --git a/src/model/dof_manager_inline_impl.cc b/src/model/dof_manager_inline_impl.cc index 0be0ecd85..71ebf49fd 100644 --- a/src/model/dof_manager_inline_impl.cc +++ b/src/model/dof_manager_inline_impl.cc @@ -1,153 +1,154 @@ /** * @file dof_manager_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 12 11:07:01 2015 + * @date creation: Thu Feb 21 2013 + * @date last modification: Wed Jan 31 2018 * - * @brief + * @brief inline functions of the dof manager * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DOF_MANAGER_INLINE_IMPL_CC__ #define __AKANTU_DOF_MANAGER_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline bool DOFManager::hasDOFs(const ID & dof_id) const { auto it = this->dofs.find(dof_id); return it != this->dofs.end(); } /* -------------------------------------------------------------------------- */ inline DOFManager::DOFData & DOFManager::getDOFData(const ID & dof_id) { auto it = this->dofs.find(dof_id); if (it == this->dofs.end()) { AKANTU_EXCEPTION("The dof " << dof_id << " does not exists in " << this->id); } return *it->second; } /* -------------------------------------------------------------------------- */ const DOFManager::DOFData & DOFManager::getDOFData(const ID & dof_id) const { auto it = this->dofs.find(dof_id); if (it == this->dofs.end()) { AKANTU_EXCEPTION("The dof " << dof_id << " does not exists in " << this->id); } return *it->second; } /* -------------------------------------------------------------------------- */ const Array<UInt> & DOFManager::getEquationsNumbers(const ID & dof_id) const { return getDOFData(dof_id).local_equation_number; } /* -------------------------------------------------------------------------- */ template <class _DOFData> inline _DOFData & DOFManager::getDOFDataTyped(const ID & dof_id) { return dynamic_cast<_DOFData &>(this->getDOFData(dof_id)); } /* -------------------------------------------------------------------------- */ template <class _DOFData> inline const _DOFData & DOFManager::getDOFDataTyped(const ID & dof_id) const { return dynamic_cast<const _DOFData &>(this->getDOFData(dof_id)); } /* -------------------------------------------------------------------------- */ inline Array<Real> & DOFManager::getDOFs(const ID & dofs_id) { return *(this->getDOFData(dofs_id).dof); } /* -------------------------------------------------------------------------- */ inline DOFSupportType DOFManager::getSupportType(const ID & dofs_id) const { return this->getDOFData(dofs_id).support_type; } /* -------------------------------------------------------------------------- */ inline Array<Real> & DOFManager::getPreviousDOFs(const ID & dofs_id) { return *(this->getDOFData(dofs_id).previous); } /* -------------------------------------------------------------------------- */ inline bool DOFManager::hasPreviousDOFs(const ID & dofs_id) const { return (this->getDOFData(dofs_id).previous != nullptr); } /* -------------------------------------------------------------------------- */ inline Array<Real> & DOFManager::getDOFsIncrement(const ID & dofs_id) { return *(this->getDOFData(dofs_id).increment); } /* -------------------------------------------------------------------------- */ inline bool DOFManager::hasDOFsIncrement(const ID & dofs_id) const { return (this->getDOFData(dofs_id).increment != nullptr); } /* -------------------------------------------------------------------------- */ inline Array<Real> & DOFManager::getDOFsDerivatives(const ID & dofs_id, UInt order) { std::vector<Array<Real> *> & derivatives = this->getDOFData(dofs_id).dof_derivatives; if ((order > derivatives.size()) || (derivatives[order - 1] == nullptr)) AKANTU_EXCEPTION("No derivatives of order " << order << " present in " << this->id << " for dof " << dofs_id); return *derivatives[order - 1]; } /* -------------------------------------------------------------------------- */ inline bool DOFManager::hasDOFsDerivatives(const ID & dofs_id, UInt order) const { const std::vector<Array<Real> *> & derivatives = this->getDOFData(dofs_id).dof_derivatives; return ((order < derivatives.size()) && (derivatives[order - 1] != nullptr)); } /* -------------------------------------------------------------------------- */ inline const Array<Real> & DOFManager::getSolution(const ID & dofs_id) const { return this->getDOFData(dofs_id).solution; } /* -------------------------------------------------------------------------- */ inline const Array<bool> & DOFManager::getBlockedDOFs(const ID & dofs_id) const { return *(this->getDOFData(dofs_id).blocked_dofs); } /* -------------------------------------------------------------------------- */ inline bool DOFManager::hasBlockedDOFs(const ID & dofs_id) const { return (this->getDOFData(dofs_id).blocked_dofs != nullptr); } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_DOF_MANAGER_INLINE_IMPL_CC__ */ diff --git a/src/model/dof_manager_petsc.cc b/src/model/dof_manager_petsc.cc index 0c168640d..2f8f332d4 100644 --- a/src/model/dof_manager_petsc.cc +++ b/src/model/dof_manager_petsc.cc @@ -1,395 +1,396 @@ /** * @file dof_manager_petsc.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Oct 5 21:19:58 2015 + * @date creation: Wed Oct 07 2015 + * @date last modification: Tue Feb 20 2018 * * @brief DOFManaterPETSc is the PETSc implementation of the DOFManager * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager_petsc.hh" #include "cppargparse.hh" #if defined(AKANTU_USE_MPI) #include "mpi_type_wrapper.hh" #include "static_communicator.hh" #endif /* -------------------------------------------------------------------------- */ #include <petscsys.h> /* -------------------------------------------------------------------------- */ namespace akantu { #if not defined(PETSC_CLANGUAGE_CXX) /// small hack to use the c binding of petsc when the cxx binding does notation /// exists int aka_PETScError(int ierr) { CHKERRQ(ierr); return 0; } #endif UInt DOFManagerPETSc::petsc_dof_manager_instances = 0; /// Error handler to make PETSc errors caught by Akantu #if PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 5 static PetscErrorCode PETScErrorHandler(MPI_Comm, int line, const char * dir, const char * file, PetscErrorCode number, PetscErrorType type, const char * message, void *) { AKANTU_ERROR("An error occured in PETSc in file \"" << file << ":" << line << "\" - PetscErrorCode " << number << " - \"" << message << "\""); } #else static PetscErrorCode PETScErrorHandler(MPI_Comm, int line, const char * func, const char * dir, const char * file, PetscErrorCode number, PetscErrorType type, const char * message, void *) { AKANTU_ERROR("An error occured in PETSc in file \"" << file << ":" << line << "\" - PetscErrorCode " << number << " - \"" << message << "\""); } #endif /* -------------------------------------------------------------------------- */ DOFManagerPETSc::DOFManagerPETSc(const ID & id, const MemoryID & memory_id) : DOFManager(id, memory_id) { // check if the akantu types and PETSc one are consistant #if __cplusplus > 199711L static_assert(sizeof(Int) == sizeof(PetscInt), "The integer type of Akantu does not match the one from PETSc"); static_assert(sizeof(Real) == sizeof(PetscReal), "The integer type of Akantu does not match the one from PETSc"); #else AKANTU_DEBUG_ASSERT( sizeof(Int) == sizeof(PetscInt), "The integer type of Akantu does not match the one from PETSc"); AKANTU_DEBUG_ASSERT( sizeof(Real) == sizeof(PetscReal), "The integer type of Akantu does not match the one from PETSc"); #endif if (this->petsc_dof_manager_instances == 0) { #if defined(AKANTU_USE_MPI) StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); const StaticCommunicatorMPI & mpi_st_comm = dynamic_cast<const StaticCommunicatorMPI &>( comm.getRealStaticCommunicator()); this->mpi_communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator(); #else this->mpi_communicator = PETSC_COMM_SELF; #endif cppargparse::ArgumentParser & argparser = getStaticArgumentParser(); int & argc = argparser.getArgC(); char **& argv = argparser.getArgV(); PetscErrorCode petsc_error = PetscInitialize(&argc, &argv, NULL, NULL); if (petsc_error != 0) { AKANTU_ERROR("An error occured while initializing Petsc (PetscErrorCode " << petsc_error << ")"); } PetscPushErrorHandler(PETScErrorHandler, NULL); this->petsc_dof_manager_instances++; } VecCreate(PETSC_COMM_WORLD, &this->residual); VecCreate(PETSC_COMM_WORLD, &this->solution); } /* -------------------------------------------------------------------------- */ DOFManagerPETSc::~DOFManagerPETSc() { PetscErrorCode ierr; ierr = VecDestroy(&(this->residual)); CHKERRXX(ierr); ierr = VecDestroy(&(this->solution)); CHKERRXX(ierr); this->petsc_dof_manager_instances--; if (this->petsc_dof_manager_instances == 0) { PetscFinalize(); } } /* -------------------------------------------------------------------------- */ void DOFManagerPETSc::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, DOFSupportType & support_type) { DOFManager::registerDOFs(dof_id, dofs_array, support_type); PetscErrorCode ierr; PetscInt current_size; ierr = VecGetSize(this->residual, ¤t_size); CHKERRXX(ierr); if (current_size == 0) { // first time vector is set PetscInt local_size = this->pure_local_system_size; ierr = VecSetSizes(this->residual, local_size, PETSC_DECIDE); CHKERRXX(ierr); ierr = VecSetFromOptions(this->residual); CHKERRXX(ierr); #ifndef AKANTU_NDEBUG PetscInt global_size; ierr = VecGetSize(this->residual, &global_size); CHKERRXX(ierr); AKANTU_DEBUG_ASSERT(this->system_size == UInt(global_size), "The local value of the system size does not match the " "one determined by PETSc"); #endif PetscInt start_dof, end_dof; VecGetOwnershipRange(this->residual, &start_dof, &end_dof); PetscInt * global_indices = new PetscInt[local_size]; global_indices[0] = start_dof; for (PetscInt d = 0; d < local_size; d++) global_indices[d + 1] = global_indices[d] + 1; // To be change if we switch to a block definition #if PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 5 ISLocalToGlobalMappingCreate(this->communicator, 1, local_size, global_indices, PETSC_COPY_VALUES, &this->is_ltog); #else ISLocalToGlobalMappingCreate(this->communicator, local_size, global_indices, PETSC_COPY_VALUES, &this->is_ltog); #endif VecSetLocalToGlobalMapping(this->residual, this->is_ltog); delete[] global_indices; ierr = VecDuplicate(this->residual, &this->solution); CHKERRXX(ierr); } else { // this is an update of the object already created AKANTU_TO_IMPLEMENT(); } /// set the solution to zero // ierr = VecZeroEntries(this->solution); // CHKERRXX(ierr); } /* -------------------------------------------------------------------------- */ /** * This function creates the non-zero pattern of the PETSc matrix. In * PETSc the parallel matrix is partitioned across processors such * that the first m0 rows belong to process 0, the next m1 rows belong * to process 1, the next m2 rows belong to process 2 etc.. where * m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores * values corresponding to [m x N] submatrix * (http://www.mcs.anl.gov/petsc/). * @param mesh mesh discretizing the domain we want to analyze * @param dof_synchronizer dof synchronizer that maps the local * dofs to the global dofs and the equation numbers, i.e., the * position at which the dof is assembled in the matrix */ // void SparseMatrixPETSc::buildProfile(const Mesh & mesh, // const DOFSynchronizer & // dof_synchronizer, // UInt nb_degree_of_freedom) { // AKANTU_DEBUG_IN(); // // clearProfile(); // this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer); // this->setSize(); // PetscErrorCode ierr; // /// resize arrays to store the number of nonzeros in each row // this->d_nnz.resize(this->local_size); // this->o_nnz.resize(this->local_size); // /// set arrays to zero everywhere // this->d_nnz.set(0); // this->o_nnz.set(0); // // if(irn_jcn_to_k) delete irn_jcn_to_k; // // irn_jcn_to_k = new std::map<std::pair<UInt, UInt>, UInt>; // coordinate_list_map::iterator irn_jcn_k_it; // Int * eq_nb_val = dof_synchronizer.getGlobalDOFEquationNumbers().storage(); // UInt nb_global_dofs = dof_synchronizer.getNbGlobalDOFs(); // Array<Int> index_pair(2); // /// Loop over all the ghost types // for (ghost_type_t::iterator gt = ghost_type_t::begin(); // gt != ghost_type_t::end(); ++gt) { // const GhostType & ghost_type = *gt; // Mesh::type_iterator it = // mesh.firstType(mesh.getSpatialDimension(), ghost_type, // _ek_not_defined); // Mesh::type_iterator end = // mesh.lastType(mesh.getSpatialDimension(), ghost_type, // _ek_not_defined); // for (; it != end; ++it) { // UInt nb_element = mesh.getNbElement(*it, ghost_type); // UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); // UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom; // UInt * conn_val = mesh.getConnectivity(*it, ghost_type).storage(); // Int * local_eq_nb_val = // new Int[nb_degree_of_freedom * nb_nodes_per_element]; // for (UInt e = 0; e < nb_element; ++e) { // Int * tmp_local_eq_nb_val = local_eq_nb_val; // for (UInt i = 0; i < nb_nodes_per_element; ++i) { // UInt n = conn_val[i]; // for (UInt d = 0; d < nb_degree_of_freedom; ++d) { // /** // * !!!!!!Careful!!!!!! This is a ugly fix. @todo this is a // * very ugly fix, because the offset for the global // * equation number, where the dof will be assembled, is // * hardcoded. In the future a class dof manager has to be // * added to Akantu to handle the mapping between the dofs // * and the equation numbers // * // */ // *tmp_local_eq_nb_val++ = // eq_nb_val[n * nb_degree_of_freedom + d] - // (dof_synchronizer.isPureGhostDOF(n * nb_degree_of_freedom + // d) // ? nb_global_dofs // : 0); // } // } // for (UInt i = 0; i < size_mat; ++i) { // Int c_irn = local_eq_nb_val[i]; // UInt j_start = 0; // for (UInt j = j_start; j < size_mat; ++j) { // Int c_jcn = local_eq_nb_val[j]; // index_pair(0) = c_irn; // index_pair(1) = c_jcn; // AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, // index_pair.storage()); // if (index_pair(0) >= first_global_index && // index_pair(0) < first_global_index + this->local_size) { // KeyCOO irn_jcn = keyPETSc(c_irn, c_jcn); // irn_jcn_k_it = irn_jcn_k.find(irn_jcn); // if (irn_jcn_k_it == irn_jcn_k.end()) { // irn_jcn_k[irn_jcn] = nb_non_zero; // // check if node is slave node // if (index_pair(1) >= first_global_index && // index_pair(1) < first_global_index + this->local_size) // this->d_nnz(index_pair(0) - first_global_index) += 1; // else // this->o_nnz(index_pair(0) - first_global_index) += 1; // nb_non_zero++; // } // } // } // } // conn_val += nb_nodes_per_element; // } // delete[] local_eq_nb_val; // } // } // // /// for pbc @todo correct it for parallel // // if(StaticCommunicator::getStaticCommunicator().getNbProc() == 1) { // // for (UInt i = 0; i < size; ++i) { // // KeyCOO irn_jcn = key(i, i); // // irn_jcn_k_it = irn_jcn_k.find(irn_jcn); // // if(irn_jcn_k_it == irn_jcn_k.end()) { // // irn_jcn_k[irn_jcn] = nb_non_zero; // // irn.push_back(i + 1); // // jcn.push_back(i + 1); // // nb_non_zero++; // // } // // } // // } // // std::string mat_type; // // mat_type.resize(20, 'a'); // // std::cout << "MatType: " << mat_type << std::endl; // // const char * mat_type_ptr = mat_type.c_str(); // MatType type; // MatGetType(this->petsc_matrix_wrapper->mat, &type); // /// std::cout << "the matrix type is: " << type << std::endl; // /** // * PETSc will use only one of the following preallocation commands // * depending on the matrix type and ignore the rest. Note that for // * the block matrix format a block size of 1 is used. This might // * result in bad performance. @todo For better results implement // * buildProfile() with larger block size. // * // */ // /// build profile: // if (strcmp(type, MATSEQAIJ) == 0) { // ierr = MatSeqAIJSetPreallocation(this->petsc_matrix_wrapper->mat, 0, // d_nnz.storage()); // CHKERRXX(ierr); // } else if ((strcmp(type, MATMPIAIJ) == 0)) { // ierr = MatMPIAIJSetPreallocation(this->petsc_matrix_wrapper->mat, 0, // d_nnz.storage(), 0, o_nnz.storage()); // CHKERRXX(ierr); // } else { // AKANTU_ERROR("The type " << type // << " of PETSc matrix is not handled by" // << " akantu in the preallocation step"); // } // // ierr = MatSeqSBAIJSetPreallocation(this->petsc_matrix_wrapper->mat, 1, // // 0, d_nnz.storage()); CHKERRXX(ierr); // if (this->sparse_matrix_type == _symmetric) { // /// set flag for symmetry to enable ICC/Cholesky preconditioner // ierr = MatSetOption(this->petsc_matrix_wrapper->mat, MAT_SYMMETRIC, // PETSC_TRUE); // CHKERRXX(ierr); // /// set flag for symmetric positive definite // ierr = MatSetOption(this->petsc_matrix_wrapper->mat, MAT_SPD, // PETSC_TRUE); // CHKERRXX(ierr); // } // /// once the profile has been build ignore any new nonzero locations // ierr = MatSetOption(this->petsc_matrix_wrapper->mat, // MAT_NEW_NONZERO_LOCATIONS, PETSC_TRUE); // CHKERRXX(ierr); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/dof_manager_petsc.hh b/src/model/dof_manager_petsc.hh index e994d5c73..8e199a964 100644 --- a/src/model/dof_manager_petsc.hh +++ b/src/model/dof_manager_petsc.hh @@ -1,173 +1,174 @@ /** * @file dof_manager_petsc.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 11 14:06:18 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Jan 31 2018 * * @brief PETSc implementation of the dof manager * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager.hh" /* -------------------------------------------------------------------------- */ #include <petscis.h> #include <petscvec.h> /* -------------------------------------------------------------------------- */ #if not defined(PETSC_CLANGUAGE_CXX) extern int aka_PETScError(int ierr); #define CHKERRXX(x) \ do { \ int error = aka_PETScError(x); \ if (error != 0) { \ AKANTU_EXCEPTION("Error in PETSC"); \ } \ } while (0) #endif #ifndef __AKANTU_DOF_MANAGER_PETSC_HH__ #define __AKANTU_DOF_MANAGER_PETSC_HH__ namespace akantu { class SparseMatrixPETSc; class DOFManagerPETSc : public DOFManager { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DOFManagerPETSc(const ID & id = "dof_manager_petsc", const MemoryID & memory_id = 0); DOFManagerPETSc(Mesh & mesh, const ID & id = "dof_manager_petsc", const MemoryID & memory_id = 0); virtual ~DOFManagerPETSc(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// register an array of degree of freedom void registerDOFs(const ID & dof_id, Array<Real> & dofs_array, DOFSupportType & support_type); /// Assemble an array to the global residual array virtual void assembleToResidual(const ID & dof_id, const Array<Real> & array_to_assemble, Real scale_factor = 1.); /** * Assemble elementary values to the global residual array. The dof number is * implicitly considered as conn(el, n) * nb_nodes_per_element + d. * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalArrayResidual( const ID & dof_id, const Array<Real> & array_to_assemble, const ElementType & type, const GhostType & ghost_type, Real scale_factor = 1.); /** * Assemble elementary values to the global residual array. The dof number is * implicitly considered as conn(el, n) * nb_nodes_per_element + d. * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat, const ElementType & type, const GhostType & ghost_type, const MatrixType & elemental_matrix_type, const Array<UInt> & filter_elements); protected: /// Get the part of the solution corresponding to the dof_id virtual void getSolutionPerDOFs(const ID & dof_id, Array<Real> & solution_array); private: /// Add a symmetric matrices to a symmetric sparse matrix inline void addSymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & element_mat, const Vector<UInt> & equation_numbers, UInt max_size); /// Add a unsymmetric matrices to a symmetric sparse matrix (i.e. cohesive /// elements) inline void addUnsymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & element_mat, const Vector<UInt> & equation_numbers, UInt max_size); /// Add a matrices to a unsymmetric sparse matrix inline void addElementalMatrixToUnsymmetric( SparseMatrixAIJ & matrix, const Matrix<Real> & element_mat, const Vector<UInt> & equation_numbers, UInt max_size); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get an instance of a new SparseMatrix virtual SparseMatrix & getNewMatrix(const ID & matrix_id, const MatrixType & matrix_type); /// Get an instance of a new SparseMatrix as a copy of the SparseMatrix /// matrix_to_copy_id virtual SparseMatrix & getNewMatrix(const ID & matrix_id, const ID & matrix_to_copy_id); /// Get the reference of an existing matrix SparseMatrixPETSc & getMatrix(const ID & matrix_id); /// Get the solution array AKANTU_GET_MACRO_NOT_CONST(GlobalSolution, this->solution, Vec &); /// Get the residual array AKANTU_GET_MACRO_NOT_CONST(Residual, this->residual, Vec &); /// Get the blocked dofs array // AKANTU_GET_MACRO(BlockedDOFs, blocked_dofs, const Array<bool> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: typedef std::map<ID, SparseMatrixPETSc *> PETScMatrixMap; /// list of matrices registered to the dof manager PETScMatrixMap petsc_matrices; /// PETSc version of the solution Vec solution; /// PETSc version of the residual Vec residual; /// PETSc local to global mapping of dofs ISLocalToGlobalMapping is_ltog; /// Communicator associated to PETSc MPI_Comm mpi_communicator; /// Static handler for petsc to know if it was initialized or not static UInt petsc_dof_manager_instances; }; } // akantu #endif /* __AKANTU_DOF_MANAGER_PETSC_HH__ */ diff --git a/src/model/heat_transfer/heat_transfer_model.cc b/src/model/heat_transfer/heat_transfer_model.cc index 031214f49..4cd6ef3ad 100644 --- a/src/model/heat_transfer/heat_transfer_model.cc +++ b/src/model/heat_transfer/heat_transfer_model.cc @@ -1,958 +1,958 @@ /** * @file heat_transfer_model.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> + * @author Emil Gallyamov <emil.gallyamov@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Srinivasa Babu Ramisetti <srinivasa.ramisetti@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Rui Wang <rui.wang@epfl.ch> * * @date creation: Sun May 01 2011 - * @date last modification: Mon Nov 30 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of HeatTransferModel 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "heat_transfer_model.hh" #include "dumpable_inline_impl.hh" #include "element_synchronizer.hh" #include "fe_engine_template.hh" #include "generalized_trapezoidal.hh" #include "group_manager_inline_impl.cc" #include "integrator_gauss.hh" #include "mesh.hh" #include "parser.hh" #include "shape_lagrange.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_element_partition.hh" #include "dumper_elemental_field.hh" #include "dumper_internal_material_field.hh" #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { namespace heat_transfer { namespace details { class ComputeRhoFunctor { public: ComputeRhoFunctor(const HeatTransferModel & model) : model(model){}; void operator()(Matrix<Real> & rho, const Element &) const { rho.set(model.getCapacity()); } private: const HeatTransferModel & model; }; } } /* -------------------------------------------------------------------------- */ HeatTransferModel::HeatTransferModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, ModelType::_heat_transfer_model, dim, id, memory_id), temperature_gradient("temperature_gradient", id), temperature_on_qpoints("temperature_on_qpoints", id), conductivity_on_qpoints("conductivity_on_qpoints", id), k_gradt_on_qpoints("k_gradt_on_qpoints", id) { AKANTU_DEBUG_IN(); conductivity = Matrix<Real>(this->spatial_dimension, this->spatial_dimension); this->initDOFManager(); this->registerDataAccessor(*this); if (this->mesh.isDistributed()) { auto & synchronizer = this->mesh.getElementSynchronizer(); this->registerSynchronizer(synchronizer, _gst_htm_capacity); this->registerSynchronizer(synchronizer, _gst_htm_temperature); this->registerSynchronizer(synchronizer, _gst_htm_gradient_temperature); } registerFEEngineObject<FEEngineType>(id + ":fem", mesh, spatial_dimension); #ifdef AKANTU_USE_IOHELPER this->mesh.registerDumper<DumperParaview>("heat_transfer", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular); #endif this->registerParam("conductivity", conductivity, _pat_parsmod); this->registerParam("conductivity_variation", conductivity_variation, 0., _pat_parsmod); this->registerParam("temperature_reference", T_ref, 0., _pat_parsmod); this->registerParam("capacity", capacity, _pat_parsmod); this->registerParam("density", density, _pat_parsmod); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initModel() { auto & fem = this->getFEEngine(); fem.initShapeFunctions(_not_ghost); fem.initShapeFunctions(_ghost); temperature_on_qpoints.initialize(fem, _nb_component = 1); temperature_gradient.initialize(fem, _nb_component = spatial_dimension); conductivity_on_qpoints.initialize( fem, _nb_component = spatial_dimension * spatial_dimension); k_gradt_on_qpoints.initialize(fem, _nb_component = spatial_dimension); } /* -------------------------------------------------------------------------- */ FEEngine & HeatTransferModel::getFEEngineBoundary(const ID & name) { return dynamic_cast<FEEngine &>(getFEEngineClassBoundary<FEEngineType>(name)); } /* -------------------------------------------------------------------------- */ template <typename T> void HeatTransferModel::allocNodalField(Array<T> *& array, const ID & name) { if (array == nullptr) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":" << name; array = &(alloc<T>(sstr_disp.str(), nb_nodes, 1, T())); } } /* -------------------------------------------------------------------------- */ HeatTransferModel::~HeatTransferModel() = default; /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleCapacityLumped(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); auto & fem = getFEEngineClass<FEEngineType>(); heat_transfer::details::ComputeRhoFunctor compute_rho(*this); for (auto & type : mesh.elementTypes(spatial_dimension, ghost_type)) { fem.assembleFieldLumped(compute_rho, "M", "temperature", this->getDOFManager(), type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MatrixType HeatTransferModel::getMatrixType(const ID & matrix_id) { if (matrix_id == "K" or matrix_id == "M") { return _symmetric; } return _mt_not_defined; } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleConductivityMatrix(); } else if (matrix_id == "M") { this->assembleCapacity(); } else { AKANTU_TO_IMPLEMENT(); } } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { this->assembleCapacityLumped(); } else { AKANTU_TO_IMPLEMENT(); } } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleResidual() { AKANTU_DEBUG_IN(); this->assembleInternalHeatRate(); this->getDOFManager().assembleToResidual("temperature", *this->external_heat_rate, 1); this->getDOFManager().assembleToResidual("temperature", *this->internal_heat_rate, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::predictor() { ++temperature_release; } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleCapacityLumped() { AKANTU_DEBUG_IN(); if (!this->getDOFManager().hasLumpedMatrix("M")) { this->getDOFManager().getNewLumpedMatrix("M"); } this->getDOFManager().clearLumpedMatrix("M"); assembleCapacityLumped(_not_ghost); assembleCapacityLumped(_ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType) { DOFManager & dof_manager = this->getDOFManager(); this->allocNodalField(this->temperature, "temperature"); this->allocNodalField(this->external_heat_rate, "external_heat_rate"); this->allocNodalField(this->internal_heat_rate, "internal_heat_rate"); this->allocNodalField(this->blocked_dofs, "blocked_dofs"); if (!dof_manager.hasDOFs("temperature")) { dof_manager.registerDOFs("temperature", *this->temperature, _dst_nodal); dof_manager.registerBlockedDOFs("temperature", *this->blocked_dofs); } if (time_step_solver_type == _tsst_dynamic || time_step_solver_type == _tsst_dynamic_lumped) { this->allocNodalField(this->temperature_rate, "temperature_rate"); if (!dof_manager.hasDOFsDerivatives("temperature", 1)) { dof_manager.registerDOFsDerivative("temperature", 1, *this->temperature_rate); } } } /* -------------------------------------------------------------------------- */ std::tuple<ID, TimeStepSolverType> HeatTransferModel::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_lumped_mass: { return std::make_tuple("explicit_lumped", _tsst_dynamic_lumped); } case _static: { return std::make_tuple("static", _tsst_static); } case _implicit_dynamic: { return std::make_tuple("implicit", _tsst_dynamic); } default: return std::make_tuple("unknown", _tsst_not_defined); } } /* -------------------------------------------------------------------------- */ ModelSolverOptions HeatTransferModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_dynamic_lumped: { options.non_linear_solver_type = _nls_lumped; options.integration_scheme_type["temperature"] = _ist_forward_euler; options.solution_type["temperature"] = IntegrationScheme::_temperature_rate; break; } case _tsst_static: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["temperature"] = _ist_pseudo_time; options.solution_type["temperature"] = IntegrationScheme::_not_defined; break; } case _tsst_dynamic: { if (this->method == _explicit_consistent_mass) { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["temperature"] = _ist_forward_euler; options.solution_type["temperature"] = IntegrationScheme::_temperature_rate; } else { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["temperature"] = _ist_trapezoidal_rule_1; options.solution_type["temperature"] = IntegrationScheme::_temperature; } break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleConductivityMatrix() { AKANTU_DEBUG_IN(); this->computeConductivityOnQuadPoints(_not_ghost); if (conductivity_release[_not_ghost] == conductivity_matrix_release) return; if (!this->getDOFManager().hasMatrix("K")) { this->getDOFManager().getNewMatrix("K", getMatrixType("K")); } this->getDOFManager().clearMatrix("K"); switch (mesh.getSpatialDimension()) { case 1: this->assembleConductivityMatrix<1>(_not_ghost); break; case 2: this->assembleConductivityMatrix<2>(_not_ghost); break; case 3: this->assembleConductivityMatrix<3>(_not_ghost); break; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void HeatTransferModel::assembleConductivityMatrix( const GhostType & ghost_type) { AKANTU_DEBUG_IN(); auto & fem = this->getFEEngine(); for (auto && type : mesh.elementTypes(spatial_dimension, ghost_type)) { auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); auto bt_d_b = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, nb_nodes_per_element * nb_nodes_per_element, "B^t*D*B"); fem.computeBtDB(conductivity_on_qpoints(type, ghost_type), *bt_d_b, 2, type, ghost_type); /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto K_e = std::make_unique<Array<Real>>( nb_element, nb_nodes_per_element * nb_nodes_per_element, "K_e"); fem.integrate(*bt_d_b, *K_e, nb_nodes_per_element * nb_nodes_per_element, type, ghost_type); this->getDOFManager().assembleElementalMatricesToMatrix( "K", "temperature", *K_e, type, ghost_type, _symmetric); } conductivity_matrix_release = conductivity_release[ghost_type]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::computeConductivityOnQuadPoints( const GhostType & ghost_type) { // if already computed once check if need to compute if (not initial_conductivity[ghost_type]) { // if temperature did not change, condictivity will not vary if (temperature_release == conductivity_release[ghost_type]) return; // if conductivity_variation is 0 no need to recompute if (conductivity_variation == 0.) return; } for (auto & type : mesh.elementTypes(spatial_dimension, ghost_type)) { auto & temperature_interpolated = temperature_on_qpoints(type, ghost_type); // compute the temperature on quadrature points this->getFEEngine().interpolateOnIntegrationPoints( *temperature, temperature_interpolated, 1, type, ghost_type); auto & cond = conductivity_on_qpoints(type, ghost_type); for (auto && tuple : zip(make_view(cond, spatial_dimension, spatial_dimension), temperature_interpolated)) { auto & C = std::get<0>(tuple); auto & T = std::get<1>(tuple); C = conductivity; Matrix<Real> variation(spatial_dimension, spatial_dimension, conductivity_variation * (T - T_ref)); // @TODO: Guillaume are you sure ? why due you compute variation then ? C += conductivity_variation; } } conductivity_release[ghost_type] = temperature_release; initial_conductivity[ghost_type] = false; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::computeKgradT(const GhostType & ghost_type) { computeConductivityOnQuadPoints(ghost_type); for (auto & type : mesh.elementTypes(spatial_dimension, ghost_type)) { auto & gradient = temperature_gradient(type, ghost_type); this->getFEEngine().gradientOnIntegrationPoints(*temperature, gradient, 1, type, ghost_type); for (auto && values : zip(make_view(conductivity_on_qpoints(type, ghost_type), spatial_dimension, spatial_dimension), make_view(gradient, spatial_dimension), make_view(k_gradt_on_qpoints(type, ghost_type), spatial_dimension))) { const auto & C = std::get<0>(values); const auto & BT = std::get<1>(values); auto & k_BT = std::get<2>(values); k_BT.mul<false>(C, BT); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleInternalHeatRate() { AKANTU_DEBUG_IN(); this->internal_heat_rate->clear(); this->synchronize(_gst_htm_temperature); auto & fem = this->getFEEngine(); for (auto ghost_type : ghost_types) { // compute k \grad T computeKgradT(ghost_type); for (auto type : mesh.elementTypes(spatial_dimension, ghost_type)) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto & k_gradt_on_qpoints_vect = k_gradt_on_qpoints(type, ghost_type); UInt nb_quad_points = k_gradt_on_qpoints_vect.size(); Array<Real> bt_k_gT(nb_quad_points, nb_nodes_per_element); fem.computeBtD(k_gradt_on_qpoints_vect, bt_k_gT, type, ghost_type); UInt nb_elements = mesh.getNbElement(type, ghost_type); Array<Real> int_bt_k_gT(nb_elements, nb_nodes_per_element); fem.integrate(bt_k_gT, int_bt_k_gT, nb_nodes_per_element, type, ghost_type); this->getDOFManager().assembleElementalArrayLocalArray( int_bt_k_gT, *this->internal_heat_rate, type, ghost_type, -1); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real el_size; Real min_el_size = std::numeric_limits<Real>::max(); Real conductivitymax = conductivity(0, 0); // get the biggest parameter from k11 until k33// for (UInt i = 0; i < spatial_dimension; i++) for (UInt j = 0; j < spatial_dimension; j++) conductivitymax = std::max(conductivity(i, j), conductivitymax); for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost)) { UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); Array<Real> coord(0, nb_nodes_per_element * spatial_dimension); FEEngine::extractNodalToElementField(mesh, mesh.getNodes(), coord, type, _not_ghost); auto el_coord = coord.begin(spatial_dimension, nb_nodes_per_element); UInt nb_element = mesh.getNbElement(type); for (UInt el = 0; el < nb_element; ++el, ++el_coord) { el_size = getFEEngine().getElementInradius(*el_coord, type); min_el_size = std::min(min_el_size, el_size); } AKANTU_DEBUG_INFO("The minimum element size : " << min_el_size << " and the max conductivity is : " << conductivitymax); } Real min_dt = 2 * min_el_size * min_el_size * density * capacity / conductivitymax; mesh.getCommunicator().allReduce(min_dt, SynchronizerOperation::_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ void HeatTransferModel::readMaterials() { auto sect = this->getParserSection(); if (not std::get<1>(sect)) { const auto & section = std::get<0>(sect); this->parseSection(section); } conductivity_on_qpoints.set(conductivity); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initFullImpl(const ModelOptions & options) { Model::initFullImpl(options); readMaterials(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleCapacity() { AKANTU_DEBUG_IN(); auto ghost_type = _not_ghost; auto & fem = getFEEngineClass<FEEngineType>(); heat_transfer::details::ComputeRhoFunctor rho_functor(*this); for (auto && type : mesh.elementTypes(spatial_dimension, ghost_type)) { fem.assembleFieldMatrix(rho_functor, "M", "temperature", this->getDOFManager(), type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); FEEngine & fem = this->getFEEngine(); UInt nb_element = mesh.getNbElement(type, ghost_type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); rho.resize(nb_element * nb_quadrature_points); rho.set(this->capacity); // Real * rho_1_val = rho.storage(); // /// compute @f$ rho @f$ for each nodes of each element // for (UInt el = 0; el < nb_element; ++el) { // for (UInt n = 0; n < nb_quadrature_points; ++n) { // *rho_1_val++ = this->capacity; // } // } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::computeThermalEnergyByNode() { AKANTU_DEBUG_IN(); Real ethermal = 0.; for (auto && pair : enumerate(make_view( *internal_heat_rate, internal_heat_rate->getNbComponent()))) { auto n = std::get<0>(pair); auto & heat_rate = std::get<1>(pair); Real heat = 0.; bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < heat_rate.size(); ++i) { if (count_node) heat += heat_rate[i] * time_step; } ethermal += heat; } mesh.getCommunicator().allReduce(ethermal, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return ethermal; } /* -------------------------------------------------------------------------- */ template <class iterator> void HeatTransferModel::getThermalEnergy( iterator Eth, Array<Real>::const_iterator<Real> T_it, Array<Real>::const_iterator<Real> T_end) const { for (; T_it != T_end; ++T_it, ++Eth) { *Eth = capacity * density * *T_it; } } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getThermalEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); Vector<Real> Eth_on_quarature_points(nb_quadrature_points); auto T_it = this->temperature_on_qpoints(type).begin(); T_it += index * nb_quadrature_points; auto T_end = T_it + nb_quadrature_points; getThermalEnergy(Eth_on_quarature_points.storage(), T_it, T_end); return getFEEngine().integrate(Eth_on_quarature_points, type, index); } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getThermalEnergy() { Real Eth = 0; auto & fem = getFEEngine(); for (auto && type : mesh.elementTypes(spatial_dimension)) { auto nb_element = mesh.getNbElement(type, _not_ghost); auto nb_quadrature_points = fem.getNbIntegrationPoints(type, _not_ghost); Array<Real> Eth_per_quad(nb_element * nb_quadrature_points, 1); auto & temperature_interpolated = temperature_on_qpoints(type); // compute the temperature on quadrature points this->getFEEngine().interpolateOnIntegrationPoints( *temperature, temperature_interpolated, 1, type); auto T_it = temperature_interpolated.begin(); auto T_end = temperature_interpolated.end(); getThermalEnergy(Eth_per_quad.begin(), T_it, T_end); Eth += fem.integrate(Eth_per_quad, type); } return Eth; } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getEnergy(const std::string & id) { AKANTU_DEBUG_IN(); Real energy = 0; if (id == "thermal") energy = getThermalEnergy(); // reduction sum over all processors mesh.getCommunicator().allReduce(energy, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getEnergy(const std::string & id, const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); Real energy = 0.; if (id == "thermal") energy = getThermalEnergy(type, index); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * HeatTransferModel::createNodalFieldBool( const std::string & field_name, const std::string & group_name, __attribute__((unused)) bool padding_flag) { std::map<std::string, Array<bool> *> uint_nodal_fields; uint_nodal_fields["blocked_dofs"] = blocked_dofs; dumper::Field * field = nullptr; field = mesh.createNodalField(uint_nodal_fields[field_name], group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createNodalFieldReal( const std::string & field_name, const std::string & group_name, __attribute__((unused)) bool padding_flag) { std::map<std::string, Array<Real> *> real_nodal_fields; real_nodal_fields["temperature"] = temperature; real_nodal_fields["temperature_rate"] = temperature_rate; real_nodal_fields["external_heat_rate"] = external_heat_rate; real_nodal_fields["internal_heat_rate"] = internal_heat_rate; real_nodal_fields["capacity_lumped"] = capacity_lumped; real_nodal_fields["increment"] = increment; dumper::Field * field = mesh.createNodalField(real_nodal_fields[field_name], group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createElementalField( const std::string & field_name, const std::string & group_name, __attribute__((unused)) bool padding_flag, __attribute__((unused)) const UInt & spatial_dimension, const ElementKind & element_kind) { dumper::Field * field = nullptr; if (field_name == "partitions") field = mesh.createElementalField<UInt, dumper::ElementPartitionField>( mesh.getConnectivities(), group_name, this->spatial_dimension, element_kind); else if (field_name == "temperature_gradient") { ElementTypeMap<UInt> nb_data_per_elem = this->mesh.getNbDataPerElem(temperature_gradient, element_kind); field = mesh.createElementalField<Real, dumper::InternalMaterialField>( temperature_gradient, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); } else if (field_name == "conductivity") { ElementTypeMap<UInt> nb_data_per_elem = this->mesh.getNbDataPerElem(conductivity_on_qpoints, element_kind); field = mesh.createElementalField<Real, dumper::InternalMaterialField>( conductivity_on_qpoints, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); } return field; } /* -------------------------------------------------------------------------- */ #else /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createElementalField( __attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag, __attribute__((unused)) const ElementKind & element_kind) { return nullptr; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createNodalFieldBool( __attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return nullptr; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createNodalFieldReal( __attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return nullptr; } #endif /* -------------------------------------------------------------------------- */ void HeatTransferModel::dump(const std::string & dumper_name) { mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::dump(const std::string & dumper_name, UInt step) { mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void HeatTransferModel::dump(const std::string & dumper_name, Real time, UInt step) { mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::dump() { mesh.dump(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::dump(UInt step) { mesh.dump(step); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::dump(Real time, UInt step) { mesh.dump(time, step); } /* -------------------------------------------------------------------------- */ inline UInt HeatTransferModel::getNbData(const Array<UInt> & indexes, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes = indexes.size(); switch (tag) { case _gst_htm_capacity: case _gst_htm_temperature: { size += nb_nodes * sizeof(Real); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void HeatTransferModel::packData(CommunicationBuffer & buffer, const Array<UInt> & indexes, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); for (auto index : indexes) { switch (tag) { case _gst_htm_capacity: buffer << (*capacity_lumped)(index); break; case _gst_htm_temperature: { buffer << (*temperature)(index); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void HeatTransferModel::unpackData(CommunicationBuffer & buffer, const Array<UInt> & indexes, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); for (auto index : indexes) { switch (tag) { case _gst_htm_capacity: { buffer >> (*capacity_lumped)(index); break; } case _gst_htm_temperature: { buffer >> (*temperature)(index); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline UInt HeatTransferModel::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes_per_element = 0; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> end = elements.end(); for (; it != end; ++it) { const Element & el = *it; nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch (tag) { case _gst_htm_capacity: { size += nb_nodes_per_element * sizeof(Real); // capacity vector break; } case _gst_htm_temperature: { size += nb_nodes_per_element * sizeof(Real); // temperature break; } case _gst_htm_gradient_temperature: { // temperature gradient size += getNbIntegrationPoints(elements) * spatial_dimension * sizeof(Real); size += nb_nodes_per_element * sizeof(Real); // nodal temperatures break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void HeatTransferModel::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { switch (tag) { case _gst_htm_capacity: { packNodalDataHelper(*capacity_lumped, buffer, elements, mesh); break; } case _gst_htm_temperature: { packNodalDataHelper(*temperature, buffer, elements, mesh); break; } case _gst_htm_gradient_temperature: { packElementalDataHelper(temperature_gradient, buffer, elements, true, getFEEngine()); packNodalDataHelper(*temperature, buffer, elements, mesh); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } } /* -------------------------------------------------------------------------- */ inline void HeatTransferModel::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { switch (tag) { case _gst_htm_capacity: { unpackNodalDataHelper(*capacity_lumped, buffer, elements, mesh); break; } case _gst_htm_temperature: { unpackNodalDataHelper(*temperature, buffer, elements, mesh); break; } case _gst_htm_gradient_temperature: { unpackElementalDataHelper(temperature_gradient, buffer, elements, true, getFEEngine()); unpackNodalDataHelper(*temperature, buffer, elements, mesh); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/heat_transfer/heat_transfer_model.hh b/src/model/heat_transfer/heat_transfer_model.hh index 723f6bf2b..1e50f36df 100644 --- a/src/model/heat_transfer/heat_transfer_model.hh +++ b/src/model/heat_transfer/heat_transfer_model.hh @@ -1,337 +1,337 @@ /** * @file heat_transfer_model.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Srinivasa Babu Ramisetti <srinivasa.ramisetti@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Rui Wang <rui.wang@epfl.ch> * * @date creation: Sun May 01 2011 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Mon Feb 05 2018 * * @brief Model of Heat Transfer * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "fe_engine.hh" #include "model.hh" /* -------------------------------------------------------------------------- */ #include <array> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_HEAT_TRANSFER_MODEL_HH__ #define __AKANTU_HEAT_TRANSFER_MODEL_HH__ namespace akantu { template <ElementKind kind, class IntegrationOrderFunctor> class IntegratorGauss; template <ElementKind kind> class ShapeLagrange; } namespace akantu { class HeatTransferModel : public Model, public DataAccessor<Element>, public DataAccessor<UInt> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using FEEngineType = FEEngineTemplate<IntegratorGauss, ShapeLagrange>; HeatTransferModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "heat_transfer_model", const MemoryID & memory_id = 0); virtual ~HeatTransferModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// generic function to initialize everything ready for explicit dynamics void initFullImpl(const ModelOptions & options) override; /// read one material file to instantiate all the materials void readMaterials(); /// allocate all vectors void initSolver(TimeStepSolverType, NonLinearSolverType) override; /// initialize the model void initModel() override; void predictor() override; /// compute the heat flux void assembleResidual() override; /// get the type of matrix needed MatrixType getMatrixType(const ID &) override; /// callback to assemble a Matrix void assembleMatrix(const ID &) override; /// callback to assemble a lumped Matrix void assembleLumpedMatrix(const ID &) override; std::tuple<ID, TimeStepSolverType> getDefaultSolverID(const AnalysisMethod & method) override; ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const; /* ------------------------------------------------------------------------ */ /* Methods for explicit */ /* ------------------------------------------------------------------------ */ public: /// compute and get the stable time step Real getStableTimeStep(); /// compute the internal heat flux void assembleInternalHeatRate(); /// calculate the lumped capacity vector for heat transfer problem void assembleCapacityLumped(); /* ------------------------------------------------------------------------ */ /* Methods for static */ /* ------------------------------------------------------------------------ */ public: /// assemble the conductivity matrix void assembleConductivityMatrix(); /// assemble the conductivity matrix void assembleCapacity(); /// compute the capacity on quadrature points void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type); private: /// calculate the lumped capacity vector for heat transfer problem (w /// ghost type) void assembleCapacityLumped(const GhostType & ghost_type); /// assemble the conductivity matrix (w/ ghost type) template <UInt dim> void assembleConductivityMatrix(const GhostType & ghost_type); /// compute the conductivity tensor for each quadrature point in an array void computeConductivityOnQuadPoints(const GhostType & ghost_type); /// compute vector k \grad T for each quadrature point void computeKgradT(const GhostType & ghost_type); /// compute the thermal energy Real computeThermalEnergyByNode(); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; inline UInt getNbData(const Array<UInt> & indexes, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<UInt> & indexes, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<UInt> & indexes, const SynchronizationTag & tag) override; /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) override; dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) override; dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & kind) override; virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); void dump() override; virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Density, density, Real); AKANTU_GET_MACRO(Capacity, capacity, Real); /// get the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the current value of the time step AKANTU_GET_MACRO(TimeStep, time_step, Real); /// get the assembled heat flux AKANTU_GET_MACRO(InternalHeatRate, *internal_heat_rate, Array<Real> &); /// get the lumped capacity AKANTU_GET_MACRO(CapacityLumped, *capacity_lumped, Array<Real> &); /// get the boundary vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &); /// get the external heat rate vector AKANTU_GET_MACRO(ExternalHeatRate, *external_heat_rate, Array<Real> &); /// get the temperature gradient AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(TemperatureGradient, temperature_gradient, Real); /// get the conductivity on q points AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ConductivityOnQpoints, conductivity_on_qpoints, Real); /// get the conductivity on q points AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(TemperatureOnQpoints, temperature_on_qpoints, Real); /// internal variables AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(KgradT, k_gradt_on_qpoints, Real); /// get the temperature AKANTU_GET_MACRO(Temperature, *temperature, Array<Real> &); /// get the temperature derivative AKANTU_GET_MACRO(TemperatureRate, *temperature_rate, Array<Real> &); /// get the energy denominated by thermal Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index); /// get the energy denominated by thermal Real getEnergy(const std::string & energy_id); /// get the thermal energy for a given element Real getThermalEnergy(const ElementType & type, UInt index); /// get the thermal energy for a given element Real getThermalEnergy(); protected: /* ------------------------------------------------------------------------ */ FEEngine & getFEEngineBoundary(const ID & name = "") override; /* ----------------------------------------------------------------------- */ template <class iterator> void getThermalEnergy(iterator Eth, Array<Real>::const_iterator<Real> T_it, Array<Real>::const_iterator<Real> T_end) const; template <typename T> void allocNodalField(Array<T> *& array, const ID & name); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// number of iterations UInt n_iter; /// time step Real time_step; /// temperatures array Array<Real> * temperature{nullptr}; /// temperatures derivatives array Array<Real> * temperature_rate{nullptr}; /// increment array (@f$\delta \dot T@f$ or @f$\delta T@f$) Array<Real> * increment{nullptr}; /// the density Real density; /// the speed of the changing temperature ElementTypeMapArray<Real> temperature_gradient; /// temperature field on quadrature points ElementTypeMapArray<Real> temperature_on_qpoints; /// conductivity tensor on quadrature points ElementTypeMapArray<Real> conductivity_on_qpoints; /// vector k \grad T on quad points ElementTypeMapArray<Real> k_gradt_on_qpoints; /// external flux vector Array<Real> * external_heat_rate{nullptr}; /// residuals array Array<Real> * internal_heat_rate{nullptr}; // lumped vector Array<Real> * capacity_lumped{nullptr}; /// boundary vector Array<bool> * blocked_dofs{nullptr}; // realtime Real time; /// capacity Real capacity; // conductivity matrix Matrix<Real> conductivity; // linear variation of the conductivity (for temperature dependent // conductivity) Real conductivity_variation; // reference temperature for the interpretation of temperature variation Real T_ref; // the biggest parameter of conductivity matrix Real conductivitymax; UInt temperature_release{0}; UInt conductivity_matrix_release{0}; std::unordered_map<GhostType, bool> initial_conductivity{{_not_ghost, true}, {_ghost, true}}; std::unordered_map<GhostType, UInt> conductivity_release{{_not_ghost, 0}, {_ghost, 0}}; }; } // akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "heat_transfer_model_inline_impl.cc" #endif /* __AKANTU_HEAT_TRANSFER_MODEL_HH__ */ diff --git a/src/model/heat_transfer/heat_transfer_model_inline_impl.cc b/src/model/heat_transfer/heat_transfer_model_inline_impl.cc index 9eca9dd79..1f10eb039 100644 --- a/src/model/heat_transfer/heat_transfer_model_inline_impl.cc +++ b/src/model/heat_transfer/heat_transfer_model_inline_impl.cc @@ -1,42 +1,42 @@ /** * @file heat_transfer_model_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Srinivasa Babu Ramisetti <srinivasa.ramisetti@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Aug 20 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of the inline functions of the HeatTransferModel 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_HEAT_TRANSFER_MODEL_INLINE_IMPL_CC__ #define __AKANTU_HEAT_TRANSFER_MODEL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_HEAT_TRANSFER_MODEL_INLINE_IMPL_CC__ */ diff --git a/src/model/integration_scheme/generalized_trapezoidal.cc b/src/model/integration_scheme/generalized_trapezoidal.cc index 9dc57650c..91d937d32 100644 --- a/src/model/integration_scheme/generalized_trapezoidal.cc +++ b/src/model/integration_scheme/generalized_trapezoidal.cc @@ -1,193 +1,193 @@ /** * @file generalized_trapezoidal.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Mon Jul 04 2011 - * @date last modification: Thu Jun 05 2014 + * @date creation: Fri Oct 23 2015 + * @date last modification: Wed Jan 31 2018 * * @brief implementation of inline functions * * @section LICENSE * - * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "generalized_trapezoidal.hh" #include "aka_array.hh" #include "dof_manager.hh" #include "mesh.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ GeneralizedTrapezoidal::GeneralizedTrapezoidal(DOFManager & dof_manager, const ID & dof_id, Real alpha) : IntegrationScheme1stOrder(dof_manager, dof_id), alpha(alpha) { this->registerParam("alpha", this->alpha, alpha, _pat_parsmod, "The alpha parameter"); } /* -------------------------------------------------------------------------- */ void GeneralizedTrapezoidal::predictor(Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & blocked_dofs) const { AKANTU_DEBUG_IN(); UInt nb_nodes = u.size(); UInt nb_degree_of_freedom = u.getNbComponent() * nb_nodes; Real * u_val = u.storage(); Real * u_dot_val = u_dot.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); for (UInt d = 0; d < nb_degree_of_freedom; d++) { if (!(*blocked_dofs_val)) { *u_val += (1. - alpha) * delta_t * *u_dot_val; } u_val++; u_dot_val++; blocked_dofs_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GeneralizedTrapezoidal::corrector(const SolutionType & type, Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const { AKANTU_DEBUG_IN(); switch (type) { case _temperature: this->allCorrector<_temperature>(delta_t, u, u_dot, blocked_dofs, delta); break; case _temperature_rate: this->allCorrector<_temperature_rate>(delta_t, u, u_dot, blocked_dofs, delta); break; default: AKANTU_EXCEPTION("The corrector type : " << type << " is not supported by this type of integration scheme"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real GeneralizedTrapezoidal::getTemperatureCoefficient( const SolutionType & type, Real delta_t) const { switch (type) { case _temperature: return 1.; case _temperature_rate: return alpha * delta_t; default: AKANTU_EXCEPTION("The corrector type : " << type << " is not supported by this type of integration scheme"); } } /* -------------------------------------------------------------------------- */ Real GeneralizedTrapezoidal::getTemperatureRateCoefficient( const SolutionType & type, Real delta_t) const { switch (type) { case _temperature: return 1. / (alpha * delta_t); case _temperature_rate: return 1.; default: AKANTU_EXCEPTION("The corrector type : " << type << " is not supported by this type of integration scheme"); } } /* -------------------------------------------------------------------------- */ template <IntegrationScheme::SolutionType type> void GeneralizedTrapezoidal::allCorrector(Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const { AKANTU_DEBUG_IN(); UInt nb_nodes = u.size(); UInt nb_degree_of_freedom = u.getNbComponent() * nb_nodes; Real e = getTemperatureCoefficient(type, delta_t); Real d = getTemperatureRateCoefficient(type, delta_t); Real * u_val = u.storage(); Real * u_dot_val = u_dot.storage(); Real * delta_val = delta.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); for (UInt dof = 0; dof < nb_degree_of_freedom; dof++) { if (!(*blocked_dofs_val)) { *u_val += e * *delta_val; *u_dot_val += d * *delta_val; } u_val++; u_dot_val++; delta_val++; blocked_dofs_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GeneralizedTrapezoidal::assembleJacobian(const SolutionType & type, Real delta_t) { AKANTU_DEBUG_IN(); SparseMatrix & J = this->dof_manager.getMatrix("J"); const SparseMatrix & M = this->dof_manager.getMatrix("M"); const SparseMatrix & K = this->dof_manager.getMatrix("K"); bool does_j_need_update = false; does_j_need_update |= M.getRelease() != m_release; does_j_need_update |= K.getRelease() != k_release; if (!does_j_need_update) { AKANTU_DEBUG_OUT(); return; } J.clear(); Real c = this->getTemperatureRateCoefficient(type, delta_t); Real e = this->getTemperatureCoefficient(type, delta_t); J.add(M, e); J.add(K, c); m_release = M.getRelease(); k_release = K.getRelease(); AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/model/integration_scheme/generalized_trapezoidal.hh b/src/model/integration_scheme/generalized_trapezoidal.hh index b984d5590..5ad22cdaf 100644 --- a/src/model/integration_scheme/generalized_trapezoidal.hh +++ b/src/model/integration_scheme/generalized_trapezoidal.hh @@ -1,166 +1,165 @@ /** * @file generalized_trapezoidal.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jul 04 2011 - * @date last modification: Fri Oct 23 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Generalized Trapezoidal Method. This implementation is taken from * Méthodes numériques en mécanique des solides by Alain Curnier \note{ISBN: * 2-88074-247-1} * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GENERALIZED_TRAPEZOIDAL_HH__ #define __AKANTU_GENERALIZED_TRAPEZOIDAL_HH__ #include "integration_scheme_1st_order.hh" namespace akantu { /** * The two differentiate equation (thermal and kinematic) are : * @f{eqnarray*}{ * C\dot{u}_{n+1} + Ku_{n+1} = q_{n+1}\\ * u_{n+1} = u_{n} + (1-\alpha) \Delta t \dot{u}_{n} + \alpha \Delta t *\dot{u}_{n+1} * @f} * * To solve it : * Predictor : * @f{eqnarray*}{ * u^0_{n+1} &=& u_{n} + (1-\alpha) \Delta t v_{n} \\ * \dot{u}^0_{n+1} &=& \dot{u}_{n} * @f} * * Solve : * @f[ (a C + b K^i_{n+1}) w = q_{n+1} - f^i_{n+1} - C \dot{u}^i_{n+1} @f] * * Corrector : * @f{eqnarray*}{ * \dot{u}^{i+1}_{n+1} &=& \dot{u}^{i}_{n+1} + a w \\ * u^{i+1}_{n+1} &=& u^{i}_{n+1} + b w * @f} * * a and b depends on the resolution method : temperature (u) or temperature *rate (@f$\dot{u}@f$) * * For temperature : @f$ w = \delta u, a = 1 / (\alpha \Delta t) , b = 1 @f$ @n * For temperature rate : @f$ w = \delta \dot{u}, a = 1, b = \alpha \Delta t @f$ */ class GeneralizedTrapezoidal : public IntegrationScheme1stOrder { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: GeneralizedTrapezoidal(DOFManager & dof_manager, const ID & dof_id, Real alpha = 0); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void predictor(Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & blocked_dofs) const override; void corrector(const SolutionType & type, Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const override; void assembleJacobian(const SolutionType & type, Real time_step) override; public: /// the coeffichent @f{b@f} in the description Real getTemperatureCoefficient(const SolutionType & type, Real delta_t) const override; /// the coeffichent @f{a@f} in the description Real getTemperatureRateCoefficient(const SolutionType & type, Real delta_t) const override; private: template <SolutionType type> void allCorrector(Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Alpha, alpha, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// the @f$\alpha@f$ parameter Real alpha; /// last release of M matrix UInt m_release; /// last release of K matrix UInt k_release; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * Forward Euler (explicit) -> condition on delta_t */ class ForwardEuler : public GeneralizedTrapezoidal { public: ForwardEuler(DOFManager & dof_manager, const ID & dof_id) : GeneralizedTrapezoidal(dof_manager, dof_id, 0.){}; std::vector<std::string> getNeededMatrixList() override { return {"M"}; } }; /** * Trapezoidal rule (implicit), midpoint rule or Crank-Nicolson */ class TrapezoidalRule1 : public GeneralizedTrapezoidal { public: TrapezoidalRule1(DOFManager & dof_manager, const ID & dof_id) : GeneralizedTrapezoidal(dof_manager, dof_id, .5){}; }; /** * Backward Euler (implicit) */ class BackwardEuler : public GeneralizedTrapezoidal { public: BackwardEuler(DOFManager & dof_manager, const ID & dof_id) : GeneralizedTrapezoidal(dof_manager, dof_id, 1.){}; }; /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_GENERALIZED_TRAPEZOIDAL_HH__ */ diff --git a/src/model/integration_scheme/integration_scheme.cc b/src/model/integration_scheme/integration_scheme.cc index dc28ebb5e..68073a71d 100644 --- a/src/model/integration_scheme/integration_scheme.cc +++ b/src/model/integration_scheme/integration_scheme.cc @@ -1,66 +1,67 @@ /** * @file integration_scheme.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Oct 23 15:33:36 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Common interface to all interface schemes * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integration_scheme.hh" #include "dof_manager.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ IntegrationScheme::IntegrationScheme(DOFManager & dof_manager, const ID & dof_id, UInt order) : Parsable(ParserType::_integration_scheme, dof_id), dof_manager(dof_manager), dof_id(dof_id), order(order) {} /* -------------------------------------------------------------------------- */ /// standard input stream operator for SolutionType std::istream & operator>>(std::istream & stream, IntegrationScheme::SolutionType & type) { std::string str; stream >> str; if (str == "displacement") type = IntegrationScheme::_displacement; else if (str == "temperature") type = IntegrationScheme::_temperature; else if (str == "velocity") type = IntegrationScheme::_velocity; else if (str == "temperature_rate") type = IntegrationScheme::_temperature_rate; else if (str == "acceleration") type = IntegrationScheme::_acceleration; else { stream.setstate(std::ios::failbit); } return stream; } } // akantu diff --git a/src/model/integration_scheme/integration_scheme.hh b/src/model/integration_scheme/integration_scheme.hh index 024313073..ccf850bf8 100644 --- a/src/model/integration_scheme/integration_scheme.hh +++ b/src/model/integration_scheme/integration_scheme.hh @@ -1,111 +1,111 @@ - /** * @file integration_scheme.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Sep 28 10:43:18 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * * @brief This class is just a base class for the integration schemes * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTEGRATION_SCHEME_HH__ #define __AKANTU_INTEGRATION_SCHEME_HH__ namespace akantu { class DOFManager; } namespace akantu { class IntegrationScheme : public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: enum SolutionType { _not_defined = -1, _displacement = 0, _temperature = 0, _velocity = 1, _temperature_rate = 1, _acceleration = 2, }; IntegrationScheme(DOFManager & dof_manager, const ID & dof_id, UInt order); ~IntegrationScheme() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// generic interface of a predictor virtual void predictor(Real delta_t) = 0; /// generic interface of a corrector virtual void corrector(const SolutionType & type, Real delta_t) = 0; /// assemble the jacobian matrix virtual void assembleJacobian(const SolutionType & type, Real delta_t) = 0; /// assemble the residual virtual void assembleResidual(bool is_lumped) = 0; /// returns a list of needed matrices virtual std::vector<std::string> getNeededMatrixList() = 0; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the order of the integration scheme UInt getOrder() const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// The underlying DOFManager DOFManager & dof_manager; /// The id of the dof treated by this integration scheme. ID dof_id; /// The order of the integrator UInt order; }; /* -------------------------------------------------------------------------- */ // std::ostream & operator<<(std::ostream & stream, // const IntegrationScheme::SolutionType & type); std::istream & operator>>(std::istream & stream, IntegrationScheme::SolutionType & type); /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_INTEGRATION_SCHEME_HH__ */ diff --git a/src/model/integration_scheme/integration_scheme_1st_order.cc b/src/model/integration_scheme/integration_scheme_1st_order.cc index e9701c486..af6e9d8e0 100644 --- a/src/model/integration_scheme/integration_scheme_1st_order.cc +++ b/src/model/integration_scheme/integration_scheme_1st_order.cc @@ -1,95 +1,96 @@ /** * @file integration_scheme_1st_order.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Oct 23 12:31:32 2015 + * @date creation: Mon Dec 13 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of the common functions for 1st order time - *integrations + * integrations * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integration_scheme_1st_order.hh" #include "dof_manager.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ std::vector<std::string> IntegrationScheme1stOrder::getNeededMatrixList() { return {"K", "M"}; } /* -------------------------------------------------------------------------- */ void IntegrationScheme1stOrder::predictor(Real delta_t) { AKANTU_DEBUG_IN(); Array<Real> & u = this->dof_manager.getDOFs(this->dof_id); Array<Real> & u_dot = this->dof_manager.getDOFsDerivatives(this->dof_id, 1); const Array<bool> & blocked_dofs = this->dof_manager.getBlockedDOFs(this->dof_id); this->predictor(delta_t, u, u_dot, blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void IntegrationScheme1stOrder::corrector(const SolutionType & type, Real delta_t) { AKANTU_DEBUG_IN(); Array<Real> & u = this->dof_manager.getDOFs(this->dof_id); Array<Real> & u_dot = this->dof_manager.getDOFsDerivatives(this->dof_id, 1); const Array<Real> & solution = this->dof_manager.getSolution(this->dof_id); const Array<bool> & blocked_dofs = this->dof_manager.getBlockedDOFs(this->dof_id); this->corrector(type, delta_t, u, u_dot, blocked_dofs, solution); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void IntegrationScheme1stOrder::assembleResidual(bool is_lumped) { AKANTU_DEBUG_IN(); const Array<Real> & first_derivative = dof_manager.getDOFsDerivatives(this->dof_id, 1); if (not is_lumped) { if (this->dof_manager.hasMatrix("M")) this->dof_manager.assembleMatMulVectToResidual(this->dof_id, "M", first_derivative, -1); } else { if (this->dof_manager.hasLumpedMatrix("M")) this->dof_manager.assembleLumpedMatMulVectToResidual( this->dof_id, "M", first_derivative, -1); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/integration_scheme/integration_scheme_1st_order.hh b/src/model/integration_scheme/integration_scheme_1st_order.hh index d15ec19df..1f77217b6 100644 --- a/src/model/integration_scheme/integration_scheme_1st_order.hh +++ b/src/model/integration_scheme/integration_scheme_1st_order.hh @@ -1,95 +1,94 @@ /** * @file integration_scheme_1st_order.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Oct 23 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Interface of the time integrator of first order * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "integration_scheme.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTEGRATION_SCHEME_1ST_ORDER_HH__ #define __AKANTU_INTEGRATION_SCHEME_1ST_ORDER_HH__ namespace akantu { class IntegrationScheme1stOrder : public IntegrationScheme { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: IntegrationScheme1stOrder(DOFManager & dof_manager, const ID & dof_id) : IntegrationScheme(dof_manager, dof_id, 1){}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get list of needed matrices std::vector<std::string> getNeededMatrixList() override; /// generic interface of a predictor void predictor(Real delta_t) override; /// generic interface of a corrector void corrector(const SolutionType & type, Real delta_t) override; /// assemble the residual void assembleResidual(bool is_lumped) override; protected: /// generic interface of a predictor of 1st order virtual void predictor(Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & boundary) const = 0; /// generic interface of a corrector of 1st order virtual void corrector(const SolutionType & type, Real delta_t, Array<Real> & u, Array<Real> & u_dot, const Array<bool> & boundary, const Array<Real> & delta) const = 0; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ protected: virtual Real getTemperatureCoefficient(const SolutionType & type, Real delta_t) const = 0; virtual Real getTemperatureRateCoefficient(const SolutionType & type, Real delta_t) const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; } // akantu #include "generalized_trapezoidal.hh" #endif /* __AKANTU_INTEGRATION_SCHEME_1ST_ORDER_HH__ */ diff --git a/src/model/integration_scheme/integration_scheme_2nd_order.cc b/src/model/integration_scheme/integration_scheme_2nd_order.cc index e308331dc..ee1dd2a39 100644 --- a/src/model/integration_scheme/integration_scheme_2nd_order.cc +++ b/src/model/integration_scheme/integration_scheme_2nd_order.cc @@ -1,105 +1,106 @@ /** * @file integration_scheme_2nd_order.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Oct 20 10:41:12 2015 + * @date creation: Fri Oct 23 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of the common part of 2nd order integration schemes * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integration_scheme_2nd_order.hh" #include "dof_manager.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ std::vector<std::string> IntegrationScheme2ndOrder::getNeededMatrixList() { return {"K", "M", "C"}; } /* -------------------------------------------------------------------------- */ void IntegrationScheme2ndOrder::predictor(Real delta_t) { AKANTU_DEBUG_IN(); Array<Real> & u = this->dof_manager.getDOFs(this->dof_id); Array<Real> & u_dot = this->dof_manager.getDOFsDerivatives(this->dof_id, 1); Array<Real> & u_dot_dot = this->dof_manager.getDOFsDerivatives(this->dof_id, 2); const Array<bool> & blocked_dofs = this->dof_manager.getBlockedDOFs(this->dof_id); this->predictor(delta_t, u, u_dot, u_dot_dot, blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void IntegrationScheme2ndOrder::corrector(const SolutionType & type, Real delta_t) { AKANTU_DEBUG_IN(); Array<Real> & u = this->dof_manager.getDOFs(this->dof_id); Array<Real> & u_dot = this->dof_manager.getDOFsDerivatives(this->dof_id, 1); Array<Real> & u_dot_dot = this->dof_manager.getDOFsDerivatives(this->dof_id, 2); const Array<Real> & solution = this->dof_manager.getSolution(this->dof_id); const Array<bool> & blocked_dofs = this->dof_manager.getBlockedDOFs(this->dof_id); this->corrector(type, delta_t, u, u_dot, u_dot_dot, blocked_dofs, solution); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void IntegrationScheme2ndOrder::assembleResidual(bool is_lumped) { AKANTU_DEBUG_IN(); if (this->dof_manager.hasMatrix("C")) { const Array<Real> & first_derivative = this->dof_manager.getDOFsDerivatives(this->dof_id, 1); this->dof_manager.assembleMatMulVectToResidual(this->dof_id, "C", first_derivative, -1); } const Array<Real> & second_derivative = this->dof_manager.getDOFsDerivatives(this->dof_id, 2); if (not is_lumped) { this->dof_manager.assembleMatMulVectToResidual(this->dof_id, "M", second_derivative, -1); } else { this->dof_manager.assembleLumpedMatMulVectToResidual(this->dof_id, "M", second_derivative, -1); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/integration_scheme/integration_scheme_2nd_order.hh b/src/model/integration_scheme/integration_scheme_2nd_order.hh index d60ee5777..d171a2e8b 100644 --- a/src/model/integration_scheme/integration_scheme_2nd_order.hh +++ b/src/model/integration_scheme/integration_scheme_2nd_order.hh @@ -1,108 +1,107 @@ /** * @file integration_scheme_2nd_order.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Oct 23 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Interface of the integrator of second order * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "integration_scheme.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTEGRATION_SCHEME_2ND_ORDER_HH__ #define __AKANTU_INTEGRATION_SCHEME_2ND_ORDER_HH__ namespace akantu { class SparseMatrix; } namespace akantu { class IntegrationScheme2ndOrder : public IntegrationScheme { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: IntegrationScheme2ndOrder(DOFManager & dof_manager, const ID & dof_id) : IntegrationScheme(dof_manager, dof_id, 2){}; ~IntegrationScheme2ndOrder() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get list of needed matrices std::vector<std::string> getNeededMatrixList() override; /// generic interface of a predictor void predictor(Real delta_t) override; /// generic interface of a corrector void corrector(const SolutionType & type, Real delta_t) override; void assembleResidual(bool is_lumped) override; protected: /// generic interface of a predictor of 2nd order virtual void predictor(Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs) const = 0; /// generic interface of a corrector of 2nd order virtual void corrector(const SolutionType & type, Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const = 0; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ protected: virtual Real getAccelerationCoefficient(const SolutionType & type, Real delta_t) const = 0; virtual Real getVelocityCoefficient(const SolutionType & type, Real delta_t) const = 0; virtual Real getDisplacementCoefficient(const SolutionType & type, Real delta_t) const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; } // akantu #include "newmark-beta.hh" #endif /* __AKANTU_INTEGRATION_SCHEME_2ND_ORDER_HH__ */ diff --git a/src/model/integration_scheme/newmark-beta.cc b/src/model/integration_scheme/newmark-beta.cc index be0d3cdeb..0831da765 100644 --- a/src/model/integration_scheme/newmark-beta.cc +++ b/src/model/integration_scheme/newmark-beta.cc @@ -1,260 +1,260 @@ /** * @file newmark-beta.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Tue Oct 05 2010 - * @date last modification: Thu Jun 05 2014 + * @date creation: Fri Oct 23 2015 + * @date last modification: Wed Jan 31 2018 * * @brief implementation of the newmark-@f$\beta@f$ integration scheme. This * implementation is taken from Méthodes numériques en mécanique des solides by * Alain Curnier \note{ISBN: 2-88074-247-1} * * @section LICENSE * - * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "newmark-beta.hh" #include "dof_manager.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NewmarkBeta::NewmarkBeta(DOFManager & dof_manager, const ID & dof_id, Real alpha, Real beta) : IntegrationScheme2ndOrder(dof_manager, dof_id), beta(beta), alpha(alpha), k(0.), h(0.), m_release(0), k_release(0), c_release(0) { this->registerParam("alpha", this->alpha, alpha, _pat_parsmod, "The alpha parameter"); this->registerParam("beta", this->beta, beta, _pat_parsmod, "The beta parameter"); } /* -------------------------------------------------------------------------- */ /* * @f$ \tilde{u_{n+1}} = u_{n} + \Delta t \dot{u}_n + \frac{\Delta t^2}{2} * \ddot{u}_n @f$ * @f$ \tilde{\dot{u}_{n+1}} = \dot{u}_{n} + \Delta t \ddot{u}_{n} @f$ * @f$ \tilde{\ddot{u}_{n}} = \ddot{u}_{n} @f$ */ void NewmarkBeta::predictor(Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs) const { AKANTU_DEBUG_IN(); UInt nb_nodes = u.size(); UInt nb_degree_of_freedom = u.getNbComponent() * nb_nodes; Real * u_val = u.storage(); Real * u_dot_val = u_dot.storage(); Real * u_dot_dot_val = u_dot_dot.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); for (UInt d = 0; d < nb_degree_of_freedom; d++) { if (!(*blocked_dofs_val)) { Real dt_a_n = delta_t * *u_dot_dot_val; *u_val += (1 - k * alpha) * delta_t * *u_dot_val + (.5 - h * alpha * beta) * delta_t * dt_a_n; *u_dot_val = (1 - k) * *u_dot_val + (1 - h * beta) * dt_a_n; *u_dot_dot_val = (1 - h) * *u_dot_dot_val; } u_val++; u_dot_val++; u_dot_dot_val++; blocked_dofs_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NewmarkBeta::corrector(const SolutionType & type, Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const { AKANTU_DEBUG_IN(); switch (type) { case _acceleration: { this->allCorrector<_acceleration>(delta_t, u, u_dot, u_dot_dot, blocked_dofs, delta); break; } case _velocity: { this->allCorrector<_velocity>(delta_t, u, u_dot, u_dot_dot, blocked_dofs, delta); break; } case _displacement: { this->allCorrector<_displacement>(delta_t, u, u_dot, u_dot_dot, blocked_dofs, delta); break; } default: AKANTU_EXCEPTION("The corrector type : " << type << " is not supported by this type of integration scheme"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real NewmarkBeta::getAccelerationCoefficient(const SolutionType & type, Real delta_t) const { switch (type) { case _acceleration: return 1.; case _velocity: return 1. / (beta * delta_t); case _displacement: return 1. / (alpha * beta * delta_t * delta_t); default: AKANTU_EXCEPTION("The corrector type : " << type << " is not supported by this type of integration scheme"); } } /* -------------------------------------------------------------------------- */ Real NewmarkBeta::getVelocityCoefficient(const SolutionType & type, Real delta_t) const { switch (type) { case _acceleration: return beta * delta_t; case _velocity: return 1.; case _displacement: return 1. / (alpha * delta_t); default: AKANTU_EXCEPTION("The corrector type : " << type << " is not supported by this type of integration scheme"); } } /* -------------------------------------------------------------------------- */ Real NewmarkBeta::getDisplacementCoefficient(const SolutionType & type, Real delta_t) const { switch (type) { case _acceleration: return alpha * beta * delta_t * delta_t; case _velocity: return alpha * delta_t; case _displacement: return 1.; default: AKANTU_EXCEPTION("The corrector type : " << type << " is not supported by this type of integration scheme"); } } /* -------------------------------------------------------------------------- */ template <IntegrationScheme::SolutionType type> void NewmarkBeta::allCorrector(Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const { AKANTU_DEBUG_IN(); UInt nb_nodes = u.size(); UInt nb_degree_of_freedom = u.getNbComponent() * nb_nodes; Real c = getAccelerationCoefficient(type, delta_t); Real d = getVelocityCoefficient(type, delta_t); Real e = getDisplacementCoefficient(type, delta_t); Real * u_val = u.storage(); Real * u_dot_val = u_dot.storage(); Real * u_dot_dot_val = u_dot_dot.storage(); Real * delta_val = delta.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); for (UInt dof = 0; dof < nb_degree_of_freedom; dof++) { if (!(*blocked_dofs_val)) { *u_val += e * *delta_val; *u_dot_val += d * *delta_val; *u_dot_dot_val += c * *delta_val; } u_val++; u_dot_val++; u_dot_dot_val++; delta_val++; blocked_dofs_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NewmarkBeta::assembleJacobian(const SolutionType & type, Real delta_t) { AKANTU_DEBUG_IN(); SparseMatrix & J = this->dof_manager.getMatrix("J"); const SparseMatrix & M = this->dof_manager.getMatrix("M"); const SparseMatrix & K = this->dof_manager.getMatrix("K"); bool does_j_need_update = false; does_j_need_update |= M.getRelease() != m_release; does_j_need_update |= K.getRelease() != k_release; if (this->dof_manager.hasMatrix("C")) { const SparseMatrix & C = this->dof_manager.getMatrix("C"); does_j_need_update |= C.getRelease() != c_release; } if (!does_j_need_update) { AKANTU_DEBUG_OUT(); return; } J.clear(); Real c = this->getAccelerationCoefficient(type, delta_t); Real e = this->getDisplacementCoefficient(type, delta_t); if (!(e == 0.)) { // in explicit this coefficient is exactly 0. J.add(K, e); } J.add(M, c); m_release = M.getRelease(); k_release = K.getRelease(); if (this->dof_manager.hasMatrix("C")) { Real d = this->getVelocityCoefficient(type, delta_t); const SparseMatrix & C = this->dof_manager.getMatrix("C"); J.add(C, d); c_release = C.getRelease(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/integration_scheme/newmark-beta.hh b/src/model/integration_scheme/newmark-beta.hh index 7373c56a9..d3742a76d 100644 --- a/src/model/integration_scheme/newmark-beta.hh +++ b/src/model/integration_scheme/newmark-beta.hh @@ -1,196 +1,195 @@ /** * @file newmark-beta.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Oct 05 2010 - * @date last modification: Fri Oct 23 2015 + * @date last modification: Wed Jan 31 2018 * * @brief implementation of the newmark-@f$\beta@f$ integration scheme. This * implementation is taken from Méthodes numériques en mécanique des solides by * Alain Curnier \note{ISBN: 2-88074-247-1} * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NEWMARK_BETA_HH__ #define __AKANTU_NEWMARK_BETA_HH__ /* -------------------------------------------------------------------------- */ #include "integration_scheme_2nd_order.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /** * The three differentiate equations (dynamic and cinematic) are : * @f{eqnarray*}{ * M \ddot{u}_{n+1} + C \dot{u}_{n+1} + K u_{n+1} &=& q_{n+1} \\ * u_{n+1} &=& u_{n} + (1 - \alpha) \Delta t \dot{u}_{n} + \alpha \Delta t *\dot{u}_{n+1} + (1/2 - \alpha) \Delta t^2 \ddot{u}_n \\ * \dot{u}_{n+1} &=& \dot{u}_{n} + (1 - \beta) \Delta t \ddot{u}_{n} + \beta *\Delta t \ddot{u}_{n+1} * @f} * * Predictor: * @f{eqnarray*}{ * u^{0}_{n+1} &=& u_{n} + \Delta t \dot{u}_n + \frac{\Delta t^2}{2} *\ddot{u}_n \\ * \dot{u}^{0}_{n+1} &=& \dot{u}_{n} + \Delta t \ddot{u}_{n} \\ * \ddot{u}^{0}_{n+1} &=& \ddot{u}_{n} * @f} * * Solve : * @f[ (c M + d C + e K^i_{n+1}) w = = q_{n+1} - f^i_{n+1} - C \dot{u}^i_{n+1} *- M \ddot{u}^i_{n+1} @f] * * Corrector : * @f{eqnarray*}{ * \ddot{u}^{i+1}_{n+1} &=& \ddot{u}^{i}_{n+1} + c w \\ * \dot{u}^{i+1}_{n+1} &=& \dot{u}^{i}_{n+1} + d w \\ * u^{i+1}_{n+1} &=& u^{i}_{n+1} + e w * @f} * * c, d and e are parameters depending on the method used to solve the equations *@n * For acceleration : @f$ w = \delta \ddot{u}, e = \alpha \beta \Delta t^2, d = *\beta \Delta t, c = 1 @f$ @n * For velocity : @f$ w = \delta \dot{u}, e = 1/\beta \Delta t, d = *1, c = \alpha \Delta t @f$ @n * For displacement : @f$ w = \delta u, e = 1, d = *1/\alpha \Delta t, c = 1/\alpha \beta \Delta t^2 @f$ */ class NewmarkBeta : public IntegrationScheme2ndOrder { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NewmarkBeta(DOFManager & dof_manager, const ID & dof_id, Real alpha = 0., Real beta = 0.); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void predictor(Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs) const override; void corrector(const SolutionType & type, Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const override; void assembleJacobian(const SolutionType & type, Real delta_t) override; public: Real getAccelerationCoefficient(const SolutionType & type, Real delta_t) const override; Real getVelocityCoefficient(const SolutionType & type, Real delta_t) const override; Real getDisplacementCoefficient(const SolutionType & type, Real delta_t) const override; private: template <SolutionType type> void allCorrector(Real delta_t, Array<Real> & u, Array<Real> & u_dot, Array<Real> & u_dot_dot, const Array<bool> & blocked_dofs, const Array<Real> & delta) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Beta, beta, Real); AKANTU_GET_MACRO(Alpha, alpha, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the @f$\beta@f$ parameter Real beta; /// the @f$\alpha@f$ parameter Real alpha; Real k; Real h; /// last release of M matrix UInt m_release; /// last release of K matrix UInt k_release; /// last release of C matrix UInt c_release; }; /** * central difference method (explicit) * undamped stability condition : * @f$ \Delta t = \alpha \Delta t_{crit} = \frac{2}{\omega_{max}} \leq \min_{e} *\frac{l_e}{c_e} * */ class CentralDifference : public NewmarkBeta { public: CentralDifference(DOFManager & dof_manager, const ID & dof_id) : NewmarkBeta(dof_manager, dof_id, 0., 1. / 2.){}; std::vector<std::string> getNeededMatrixList() override { return {"M", "C"}; } }; //#include "integration_scheme/central_difference.hh" /// undamped trapezoidal rule (implicit) class TrapezoidalRule2 : public NewmarkBeta { public: TrapezoidalRule2(DOFManager & dof_manager, const ID & dof_id) : NewmarkBeta(dof_manager, dof_id, 1. / 2., 1. / 2.){}; }; /// Fox-Goodwin rule (implicit) class FoxGoodwin : public NewmarkBeta { public: FoxGoodwin(DOFManager & dof_manager, const ID & dof_id) : NewmarkBeta(dof_manager, dof_id, 1. / 6., 1. / 2.){}; }; /// Linear acceleration (implicit) class LinearAceleration : public NewmarkBeta { public: LinearAceleration(DOFManager & dof_manager, const ID & dof_id) : NewmarkBeta(dof_manager, dof_id, 1. / 3., 1. / 2.){}; }; /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_NEWMARK_BETA_HH__ */ diff --git a/src/model/integration_scheme/pseudo_time.cc b/src/model/integration_scheme/pseudo_time.cc index 6b350562d..1ca15129b 100644 --- a/src/model/integration_scheme/pseudo_time.cc +++ b/src/model/integration_scheme/pseudo_time.cc @@ -1,81 +1,82 @@ /** * @file pseudo_time.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Feb 17 09:49:10 2016 + * @date creation: Fri Feb 19 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of a really simple integration scheme * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "pseudo_time.hh" #include "dof_manager.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ PseudoTime::PseudoTime(DOFManager & dof_manager, const ID & dof_id) : IntegrationScheme(dof_manager, dof_id, 0), k_release(0) {} /* -------------------------------------------------------------------------- */ std::vector<std::string> PseudoTime::getNeededMatrixList() { return {"K"}; } /* -------------------------------------------------------------------------- */ void PseudoTime::predictor(Real) {} /* -------------------------------------------------------------------------- */ void PseudoTime::corrector(const SolutionType &, Real) { auto & us = this->dof_manager.getDOFs(this->dof_id); const auto & deltas = this->dof_manager.getSolution(this->dof_id); const auto & blocked_dofs = this->dof_manager.getBlockedDOFs(this->dof_id); for (auto && tuple : zip(make_view(us), deltas, make_view(blocked_dofs))) { auto & u = std::get<0>(tuple); const auto & delta = std::get<1>(tuple); const auto & bld = std::get<2>(tuple); if (not bld) u += delta; } } /* -------------------------------------------------------------------------- */ void PseudoTime::assembleJacobian(const SolutionType &, Real) { SparseMatrix & J = this->dof_manager.getMatrix("J"); const SparseMatrix & K = this->dof_manager.getMatrix("K"); if (K.getRelease() == k_release) return; J.clear(); J.add(K); k_release = K.getRelease(); } /* -------------------------------------------------------------------------- */ void PseudoTime::assembleResidual(bool) {} /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/integration_scheme/pseudo_time.hh b/src/model/integration_scheme/pseudo_time.hh index 8950f86b1..a93e66986 100644 --- a/src/model/integration_scheme/pseudo_time.hh +++ b/src/model/integration_scheme/pseudo_time.hh @@ -1,72 +1,73 @@ /** * @file pseudo_time.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Feb 17 09:46:05 2016 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Pseudo time integration scheme * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integration_scheme.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PSEUDO_TIME_HH__ #define __AKANTU_PSEUDO_TIME_HH__ namespace akantu { class PseudoTime : public IntegrationScheme { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PseudoTime(DOFManager & dof_manager, const ID & dof_id); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get list of needed matrices std::vector<std::string> getNeededMatrixList() override; /// generic interface of a predictor void predictor(Real delta_t) override; /// generic interface of a corrector void corrector(const SolutionType & type, Real delta_t) override; /// assemble the jacobian matrix void assembleJacobian(const SolutionType & type, Real delta_t) override; /// assemble the residual void assembleResidual(bool is_lumped) override; protected: /// last release of K matrix UInt k_release; }; } // namespace akantu #endif /* __AKANTU_PSEUDO_TIME_HH__ */ diff --git a/src/model/model.cc b/src/model/model.cc index 959a2fba5..9a4a9577a 100644 --- a/src/model/model.cc +++ b/src/model/model.cc @@ -1,369 +1,369 @@ /** * @file model.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Oct 03 2011 - * @date last modification: Thu Nov 19 2015 + * @date last modification: Tue Feb 20 2018 * * @brief implementation of model common parts * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "model.hh" #include "communicator.hh" #include "data_accessor.hh" #include "element_group.hh" #include "element_synchronizer.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Model::Model(Mesh & mesh, const ModelType & type, UInt dim, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), ModelSolver(mesh, type, id, memory_id), mesh(mesh), spatial_dimension(dim == _all_dimensions ? mesh.getSpatialDimension() : dim), is_pbc_slave_node(0, 1, "is_pbc_slave_node"), parser(getStaticParser()) { AKANTU_DEBUG_IN(); this->mesh.registerEventHandler(*this, _ehp_model); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Model::~Model() = default; /* -------------------------------------------------------------------------- */ // void Model::setParser(Parser & parser) { this->parser = &parser; } /* -------------------------------------------------------------------------- */ void Model::initFullImpl(const ModelOptions & options) { AKANTU_DEBUG_IN(); method = options.analysis_method; if (!this->hasDefaultSolver()) { this->initNewSolver(this->method); } initModel(); initFEEngineBoundary(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Model::initNewSolver(const AnalysisMethod & method) { ID solver_name; TimeStepSolverType tss_type; std::tie(solver_name, tss_type) = this->getDefaultSolverID(method); if (not this->hasSolver(solver_name)) { ModelSolverOptions options = this->getDefaultSolverOptions(tss_type); this->getNewSolver(solver_name, tss_type, options.non_linear_solver_type); for (auto && is_type : options.integration_scheme_type) { if (!this->hasIntegrationScheme(solver_name, is_type.first)) { this->setIntegrationScheme(solver_name, is_type.first, is_type.second, options.solution_type[is_type.first]); } } } this->method = method; this->setDefaultSolver(solver_name); } /* -------------------------------------------------------------------------- */ void Model::initPBC() { auto it = pbc_pair.begin(); auto end = pbc_pair.end(); is_pbc_slave_node.resize(mesh.getNbNodes()); #ifndef AKANTU_NDEBUG auto coord_it = mesh.getNodes().begin(this->spatial_dimension); #endif while (it != end) { UInt i1 = (*it).first; is_pbc_slave_node(i1) = true; #ifndef AKANTU_NDEBUG UInt i2 = (*it).second; UInt slave = mesh.isDistributed() ? mesh.getGlobalNodesIds()(i1) : i1; UInt master = mesh.isDistributed() ? mesh.getGlobalNodesIds()(i2) : i2; AKANTU_DEBUG_INFO("pairing " << slave << " (" << Vector<Real>(coord_it[i1]) << ") with " << master << " (" << Vector<Real>(coord_it[i2]) << ")"); #endif ++it; } } /* -------------------------------------------------------------------------- */ void Model::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_not_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_ghost); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name, const std::string & dumper_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup() { auto bit = mesh.element_group_begin(); auto bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->dump(); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory) { auto bit = mesh.element_group_begin(); auto bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->setDirectory(directory); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setGroupBaseName(const std::string & basename, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setBaseName(basename); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Model::getGroupDumper(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); return group.getDumper(); } /* -------------------------------------------------------------------------- */ // DUMPER stuff /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & field_id, dumper::Field * field, DumperIOHelper & dumper) { #ifdef AKANTU_USE_IOHELPER dumper.registerField(field_id, field); #endif } /* -------------------------------------------------------------------------- */ void Model::addDumpField(const std::string & field_id) { this->addDumpFieldToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVector(const std::string & field_id) { this->addDumpFieldVectorToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensor(const std::string & field_id) { this->addDumpFieldTensorToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseName(const std::string & field_id) { mesh.setBaseName(field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseNameToDumper(const std::string & dumper_name, const std::string & basename) { mesh.setBaseNameToDumper(dumper_name, basename); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, false); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldToDumper(group.getDefaultDumperName(), field_id, group_name, _ek_regular, false); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->removeDumpGroupFieldFromDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.removeDumpFieldFromDumper(dumper_name, field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldVectorToDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { this->addDumpGroupFieldToDumper(dumper_name, field_id, group_name, _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { this->addDumpGroupFieldToDumper(dumper_name, field_id, group_name, this->spatial_dimension, element_kind, padding_flag); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, UInt spatial_dimension, const ElementKind & element_kind, bool padding_flag) { #ifdef AKANTU_USE_IOHELPER dumper::Field * field = nullptr; if (!field) field = this->createNodalFieldReal(field_id, group_name, padding_flag); if (!field) field = this->createNodalFieldUInt(field_id, group_name, padding_flag); if (!field) field = this->createNodalFieldBool(field_id, group_name, padding_flag); if (!field) field = this->createElementalField(field_id, group_name, padding_flag, spatial_dimension, element_kind); if (!field) field = this->mesh.createFieldFromAttachedData<UInt>(field_id, group_name, element_kind); if (!field) field = this->mesh.createFieldFromAttachedData<Real>(field_id, group_name, element_kind); #ifndef AKANTU_NDEBUG if (!field) { AKANTU_DEBUG_WARNING("No field could be found based on name: " << field_id); } #endif if (field) { DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name, group_name); this->addDumpGroupFieldToDumper(field_id, field, dumper); } #endif } /* -------------------------------------------------------------------------- */ void Model::dump() { mesh.dump(); } /* -------------------------------------------------------------------------- */ void Model::setDirectory(const std::string & directory) { mesh.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setDirectoryToDumper(const std::string & dumper_name, const std::string & directory) { mesh.setDirectoryToDumper(dumper_name, directory); } /* -------------------------------------------------------------------------- */ void Model::setTextModeToDumper() { mesh.setTextModeToDumper(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/model.hh b/src/model/model.hh index af1032fae..b162476fd 100644 --- a/src/model/model.hh +++ b/src/model/model.hh @@ -1,376 +1,376 @@ /** * @file model.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Oct 16 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Interface of a model * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "aka_named_argument.hh" #include "fe_engine.hh" #include "mesh.hh" #include "model_options.hh" #include "model_solver.hh" /* -------------------------------------------------------------------------- */ #include <typeindex> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MODEL_HH__ #define __AKANTU_MODEL_HH__ namespace akantu { class SynchronizerRegistry; class Parser; class DumperIOHelper; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { class Model : public Memory, public ModelSolver, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Model(Mesh & mesh, const ModelType & type, UInt spatial_dimension = _all_dimensions, const ID & id = "model", const MemoryID & memory_id = 0); ~Model() override; using FEEngineMap = std::map<std::string, std::unique_ptr<FEEngine>>; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: virtual void initFullImpl(const ModelOptions & options); public: #ifndef SWIG template <typename... pack> std::enable_if_t<are_named_argument<pack...>::value> initFull(pack &&... _pack) { switch (this->model_type) { #ifdef AKANTU_SOLID_MECHANICS case ModelType::_solid_mechanics_model: this->initFullImpl(SolidMechanicsModelOptions{ use_named_args, std::forward<decltype(_pack)>(_pack)...}); break; #endif #ifdef AKANTU_COHESIVE_ELEMENT case ModelType::_solid_mechanics_model_cohesive: this->initFullImpl(SolidMechanicsModelCohesiveOptions{ use_named_args, std::forward<decltype(_pack)>(_pack)...}); break; #endif #ifdef AKANTU_HEAT_TRANSFER case ModelType::_heat_transfer_model: this->initFullImpl(HeatTransferModelOptions{ use_named_args, std::forward<decltype(_pack)>(_pack)...}); break; #endif #ifdef AKANTU_EMBEDDED case ModelType::_embedded_model: this->initFullImpl(EmbeddedInterfaceModelOptions{ use_named_args, std::forward<decltype(_pack)>(_pack)...}); break; #endif default: this->initFullImpl(ModelOptions{use_named_args, std::forward<decltype(_pack)>(_pack)...}); } } template <typename... pack> std::enable_if_t<not are_named_argument<pack...>::value> initFull(pack &&... _pack) { this->initFullImpl(std::forward<decltype(_pack)>(_pack)...); } #endif /// initialize a new solver if needed void initNewSolver(const AnalysisMethod & method); protected: /// get some default values for derived classes virtual std::tuple<ID, TimeStepSolverType> getDefaultSolverID(const AnalysisMethod & method) = 0; virtual void initModel() = 0; virtual void initFEEngineBoundary(); // /// change local equation number so that PBC is assembled properly // void changeLocalEquationNumberForPBC(std::map<UInt, UInt> & pbc_pair, // UInt dimension); /// function to print the containt of the class void printself(std::ostream &, int = 0) const override{}; // /// initialize the model for PBC // void setPBC(UInt x, UInt y, UInt z); // void setPBC(SurfacePairList & surface_pairs); public: virtual void initPBC(); /// set the parser to use // void setParser(Parser & parser); /* ------------------------------------------------------------------------ */ /* Access to the dumpable interface of the boundaries */ /* ------------------------------------------------------------------------ */ /// Dump the data for a given group void dumpGroup(const std::string & group_name); void dumpGroup(const std::string & group_name, const std::string & dumper_name); /// Dump the data for all boundaries void dumpGroup(); /// Set the directory for a given group void setGroupDirectory(const std::string & directory, const std::string & group_name); /// Set the directory for all boundaries void setGroupDirectory(const std::string & directory); /// Set the base name for a given group void setGroupBaseName(const std::string & basename, const std::string & group_name); /// Get the internal dumper of a given group DumperIOHelper & getGroupDumper(const std::string & group_name); /* ------------------------------------------------------------------------ */ /* Function for non local capabilities */ /* ------------------------------------------------------------------------ */ virtual void updateDataForNonLocalCriterion(__attribute__((unused)) ElementTypeMapReal & criterion) { AKANTU_TO_IMPLEMENT(); } protected: template <typename T> void allocNodalField(Array<T> *& array, UInt nb_component, const ID & name); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get id of model AKANTU_GET_MACRO(ID, id, const ID) /// get the number of surfaces AKANTU_GET_MACRO(Mesh, mesh, Mesh &) /// synchronize the boundary in case of parallel run virtual void synchronizeBoundaries(){}; /// return the fem object associated with a provided name inline FEEngine & getFEEngine(const ID & name = "") const; /// return the fem boundary object associated with a provided name virtual FEEngine & getFEEngineBoundary(const ID & name = ""); /// register a fem object associated with name template <typename FEEngineClass> inline void registerFEEngineObject(const std::string & name, Mesh & mesh, UInt spatial_dimension); /// unregister a fem object associated with name inline void unRegisterFEEngineObject(const std::string & name); /// return the synchronizer registry SynchronizerRegistry & getSynchronizerRegistry(); /// return the fem object associated with a provided name template <typename FEEngineClass> inline FEEngineClass & getFEEngineClass(std::string name = "") const; /// return the fem boundary object associated with a provided name template <typename FEEngineClass> inline FEEngineClass & getFEEngineClassBoundary(std::string name = ""); /// get the pbc pairs std::map<UInt, UInt> & getPBCPairs() { return pbc_pair; }; /// returns if node is slave in pbc inline bool isPBCSlaveNode(const UInt) const { throw; return false; /* TODO repair PBC*/ } /// returns the array of pbc slave nodes (boolean information) AKANTU_GET_MACRO(IsPBCSlaveNode, is_pbc_slave_node, const Array<bool> &) /// Get the type of analysis method used AKANTU_GET_MACRO(AnalysisMethod, method, AnalysisMethod); /* ------------------------------------------------------------------------ */ /* Pack and unpack helper functions */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbIntegrationPoints(const Array<Element> & elements, const ID & fem_id = ID()) const; /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ void setTextModeToDumper(); virtual void addDumpGroupFieldToDumper(const std::string & field_id, dumper::Field * field, DumperIOHelper & dumper); virtual void addDumpField(const std::string & field_id); virtual void addDumpFieldVector(const std::string & field_id); virtual void addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldTensor(const std::string & field_id); virtual void setBaseName(const std::string & basename); virtual void setBaseNameToDumper(const std::string & dumper_name, const std::string & basename); virtual void addDumpGroupField(const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag); virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, UInt spatial_dimension, const ElementKind & element_kind, bool padding_flag); virtual void removeDumpGroupField(const std::string & field_id, const std::string & group_name); virtual void removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual dumper::Field * createNodalFieldReal(__attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return nullptr; } virtual dumper::Field * createNodalFieldUInt(__attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return nullptr; } virtual dumper::Field * createNodalFieldBool(__attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return nullptr; } virtual dumper::Field * createElementalField(__attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag, __attribute__((unused)) const UInt & spatial_dimension, __attribute__((unused)) const ElementKind & kind) { return nullptr; } void setDirectory(const std::string & directory); void setDirectoryToDumper(const std::string & dumper_name, const std::string & directory); virtual void dump(); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: friend std::ostream & operator<<(std::ostream &, const Model &); /// analysis method check the list in akantu::AnalysisMethod AnalysisMethod method; /// Mesh Mesh & mesh; /// Spatial dimension of the problem UInt spatial_dimension; /// the main fem object present in all models FEEngineMap fems; /// the fem object present in all models for boundaries FEEngineMap fems_boundary; /// default fem object std::string default_fem; /// pbc pairs std::map<UInt, UInt> pbc_pair; /// flag per node to know is pbc slave Array<bool> is_pbc_slave_node; /// parser to the pointer to use Parser & parser; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Model & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "model_inline_impl.cc" #endif /* __AKANTU_MODEL_HH__ */ diff --git a/src/model/model_inline_impl.cc b/src/model/model_inline_impl.cc index c57bbf7ed..c786190ed 100644 --- a/src/model/model_inline_impl.cc +++ b/src/model/model_inline_impl.cc @@ -1,217 +1,216 @@ /** * @file model_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 25 2010 - * @date last modification: Wed Nov 11 2015 + * @date last modification: Wed Nov 08 2017 * * @brief inline implementation of the model 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MODEL_INLINE_IMPL_CC__ #define __AKANTU_MODEL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename FEEngineClass> inline FEEngineClass & Model::getFEEngineClassBoundary(std::string name) { AKANTU_DEBUG_IN(); if (name == "") name = default_fem; FEEngineMap::const_iterator it_boun = fems_boundary.find(name); if (it_boun == fems_boundary.end()) { AKANTU_DEBUG_INFO("Creating FEEngine boundary " << name); FEEngineMap::const_iterator it = fems.find(name); AKANTU_DEBUG_ASSERT(it != fems.end(), "The FEEngine " << name << " is not registered"); UInt spatial_dimension = it->second->getElementDimension(); std::stringstream sstr; sstr << id << ":fem_boundary:" << name; fems_boundary[name] = std::make_unique<FEEngineClass>( it->second->getMesh(), spatial_dimension - 1, sstr.str(), memory_id); } AKANTU_DEBUG_OUT(); return dynamic_cast<FEEngineClass &>(*fems_boundary[name]); } /* -------------------------------------------------------------------------- */ template <typename FEEngineClass> inline FEEngineClass & Model::getFEEngineClass(std::string name) const { AKANTU_DEBUG_IN(); if (name == "") name = default_fem; auto it = fems.find(name); AKANTU_DEBUG_ASSERT(it != fems.end(), "The FEEngine " << name << " is not registered"); AKANTU_DEBUG_OUT(); return dynamic_cast<FEEngineClass &>(*(it->second)); } /* -------------------------------------------------------------------------- */ inline void Model::unRegisterFEEngineObject(const std::string & name) { auto it = fems.find(name); AKANTU_DEBUG_ASSERT(it != fems.end(), "FEEngine object with name " << name << " was not found"); fems.erase(it); if (!fems.empty()) default_fem = (*fems.begin()).first; } /* -------------------------------------------------------------------------- */ template <typename FEEngineClass> inline void Model::registerFEEngineObject(const std::string & name, Mesh & mesh, UInt spatial_dimension) { if (fems.size() == 0) default_fem = name; #ifndef AKANTU_NDEBUG auto it = fems.find(name); AKANTU_DEBUG_ASSERT(it == fems.end(), "FEEngine object with name " << name << " was already created"); #endif std::stringstream sstr; sstr << id << ":fem:" << name << memory_id; fems[name] = std::make_unique<FEEngineClass>(mesh, spatial_dimension, sstr.str(), memory_id); } /* -------------------------------------------------------------------------- */ inline FEEngine & Model::getFEEngine(const ID & name) const { AKANTU_DEBUG_IN(); ID tmp_name = name; if (name == "") tmp_name = default_fem; auto it = fems.find(tmp_name); AKANTU_DEBUG_ASSERT(it != fems.end(), "The FEEngine " << tmp_name << " is not registered"); AKANTU_DEBUG_OUT(); return *(it->second); } /* -------------------------------------------------------------------------- */ inline FEEngine & Model::getFEEngineBoundary(const ID & name) { AKANTU_DEBUG_IN(); ID tmp_name = name; if (name == "") tmp_name = default_fem; FEEngineMap::const_iterator it = fems_boundary.find(tmp_name); AKANTU_DEBUG_ASSERT(it != fems_boundary.end(), "The FEEngine boundary " << tmp_name << " is not registered"); AKANTU_DEBUG_ASSERT(it->second != nullptr, "The FEEngine boundary " << tmp_name << " was not created"); AKANTU_DEBUG_OUT(); return *(it->second); } // /* -------------------------------------------------------------------------- // */ // /// @todo : should merge with a single function which handles local and // global // inline void Model::changeLocalEquationNumberForPBC(std::map<UInt,UInt> & // pbc_pair, // UInt dimension){ // for (std::map<UInt,UInt>::iterator it = pbc_pair.begin(); // it != pbc_pair.end();++it) { // Int node_master = (*it).second; // Int node_slave = (*it).first; // for (UInt i = 0; i < dimension; ++i) { // (*dof_synchronizer->getLocalDOFEquationNumbersPointer()) // (node_slave*dimension+i) = dimension*node_master+i; // (*dof_synchronizer->getGlobalDOFEquationNumbersPointer()) // (node_slave*dimension+i) = dimension*node_master+i; // } // } // } // /* -------------------------------------------------------------------------- // */ // inline bool Model::isPBCSlaveNode(const UInt node) const { // // if no pbc is defined, is_pbc_slave_node is of size zero // if (is_pbc_slave_node.size() == 0) // return false; // else // return is_pbc_slave_node(node); // } /* -------------------------------------------------------------------------- */ template <typename T> void Model::allocNodalField(Array<T> *& array, UInt nb_component, const ID & name) { if (array == nullptr) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":" << name; array = &(alloc<T>(sstr_disp.str(), nb_nodes, nb_component, T())); } } /* -------------------------------------------------------------------------- */ inline UInt Model::getNbIntegrationPoints(const Array<Element> & elements, const ID & fem_id) const { UInt nb_quad = 0; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> end = elements.end(); for (; it != end; ++it) { const Element & el = *it; nb_quad += getFEEngine(fem_id).getNbIntegrationPoints(el.type, el.ghost_type); } return nb_quad; } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_MODEL_INLINE_IMPL_CC__ */ diff --git a/src/model/model_options.hh b/src/model/model_options.hh index c431d6931..7e2e0a15c 100644 --- a/src/model/model_options.hh +++ b/src/model/model_options.hh @@ -1,137 +1,139 @@ /** * @file model_options.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Mon Dec 04 2017 + * @date creation: Mon Dec 04 2017 + * @date last modification: Wed Jan 31 2018 * - * @brief A Documented file. + * @brief A Documented file. * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_named_argument.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MODEL_OPTIONS_HH__ #define __AKANTU_MODEL_OPTIONS_HH__ namespace akantu { namespace { DECLARE_NAMED_ARGUMENT(analysis_method); } struct ModelOptions { explicit ModelOptions(AnalysisMethod analysis_method = _static) : analysis_method(analysis_method) {} template <typename... pack> ModelOptions(use_named_args_t, pack &&... _pack) : ModelOptions(OPTIONAL_NAMED_ARG(analysis_method, _static)) {} virtual ~ModelOptions() = default; AnalysisMethod analysis_method; }; #ifdef AKANTU_SOLID_MECHANICS /* -------------------------------------------------------------------------- */ struct SolidMechanicsModelOptions : public ModelOptions { explicit SolidMechanicsModelOptions( AnalysisMethod analysis_method = _explicit_lumped_mass) : ModelOptions(analysis_method) {} template <typename... pack> SolidMechanicsModelOptions(use_named_args_t, pack &&... _pack) : SolidMechanicsModelOptions( OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass)) {} }; #endif /* -------------------------------------------------------------------------- */ #ifdef AKANTU_COHESIVE_ELEMENT namespace { DECLARE_NAMED_ARGUMENT(is_extrinsic); } /* -------------------------------------------------------------------------- */ struct SolidMechanicsModelCohesiveOptions : public SolidMechanicsModelOptions { SolidMechanicsModelCohesiveOptions( AnalysisMethod analysis_method = _explicit_lumped_mass, bool extrinsic = false) : SolidMechanicsModelOptions(analysis_method), extrinsic(extrinsic) {} template <typename... pack> SolidMechanicsModelCohesiveOptions(use_named_args_t, pack &&... _pack) : SolidMechanicsModelCohesiveOptions( OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass), OPTIONAL_NAMED_ARG(is_extrinsic, false)) {} bool extrinsic{false}; }; #endif #ifdef AKANTU_HEAT_TRANSFER /* -------------------------------------------------------------------------- */ struct HeatTransferModelOptions : public ModelOptions { explicit HeatTransferModelOptions( AnalysisMethod analysis_method = _explicit_lumped_mass) : ModelOptions(analysis_method) {} template <typename... pack> HeatTransferModelOptions(use_named_args_t, pack &&... _pack) : HeatTransferModelOptions( OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass)) {} }; #endif #ifdef AKANTU_EMBEDDED namespace { DECLARE_NAMED_ARGUMENT(init_intersections); } /* -------------------------------------------------------------------------- */ struct EmbeddedInterfaceModelOptions : SolidMechanicsModelOptions { /** * @brief Constructor for EmbeddedInterfaceModelOptions * @param analysis_method see SolidMechanicsModelOptions * @param init_intersections compute intersections */ EmbeddedInterfaceModelOptions( AnalysisMethod analysis_method = _explicit_lumped_mass, bool init_intersections = true) : SolidMechanicsModelOptions(analysis_method), has_intersections(init_intersections) {} template <typename... pack> EmbeddedInterfaceModelOptions(use_named_args_t, pack &&... _pack) : EmbeddedInterfaceModelOptions( OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass), OPTIONAL_NAMED_ARG(init_intersections, true)) {} /// Should consider reinforcements bool has_intersections; }; #endif } // akantu #endif /* __AKANTU_MODEL_OPTIONS_HH__ */ diff --git a/src/model/model_solver.cc b/src/model/model_solver.cc index 78e97c629..1891e7fd3 100644 --- a/src/model/model_solver.cc +++ b/src/model/model_solver.cc @@ -1,364 +1,365 @@ /** * @file model_solver.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 12 13:31:56 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of ModelSolver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "model_solver.hh" #include "dof_manager.hh" #include "dof_manager_default.hh" #include "mesh.hh" #include "non_linear_solver.hh" #include "time_step_solver.hh" #if defined(AKANTU_USE_PETSC) #include "dof_manager_petsc.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> static T getOptionToType(const std::string & opt_str) { std::stringstream sstr(opt_str); T opt; sstr >> opt; return opt; } /* -------------------------------------------------------------------------- */ ModelSolver::ModelSolver(Mesh & mesh, const ModelType & type, const ID & id, UInt memory_id) : Parsable(ParserType::_model, id), SolverCallback(), model_type(type), parent_id(id), parent_memory_id(memory_id), mesh(mesh), dof_manager(nullptr), default_solver_id("") {} /* -------------------------------------------------------------------------- */ ModelSolver::~ModelSolver() = default; /* -------------------------------------------------------------------------- */ std::tuple<ParserSection, bool> ModelSolver::getParserSection() { auto sub_sections = getStaticParser().getSubSections(ParserType::_model); auto it = std::find_if( sub_sections.begin(), sub_sections.end(), [&](auto && section) { ModelType type = getOptionToType<ModelType>(section.getName()); // default id should be the model type if not defined std::string name = section.getParameter("name", this->parent_id); return type == model_type and name == this->parent_id; }); if (it == sub_sections.end()) return std::make_tuple(ParserSection(), true); return std::make_tuple(*it, false); } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager() { // default without external solver activated at compilation same as mumps that // is the historical solver but with only the lumped solver ID solver_type = "default"; #if defined(AKANTU_USE_MUMPS) solver_type = "default"; #elif defined(AKANTU_USE_PETSC) solver_type = "petsc"; #endif ParserSection section; bool is_empty; std::tie(section, is_empty) = this->getParserSection(); if (not is_empty) { solver_type = section.getOption(solver_type); this->initDOFManager(section, solver_type); } else { this->initDOFManager(solver_type); } } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager(const ID & solver_type) { try { this->dof_manager = DOFManagerFactory::getInstance().allocate( solver_type, mesh, this->parent_id + ":dof_manager" + solver_type, this->parent_memory_id); } catch (...) { AKANTU_EXCEPTION( "To use the solver " << solver_type << " you will have to code it. This is an unknown solver type."); } this->setDOFManager(*this->dof_manager); } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager(const ParserSection & section, const ID & solver_type) { this->initDOFManager(solver_type); auto sub_sections = section.getSubSections(ParserType::_time_step_solver); // parsing the time step solvers for (auto && section : sub_sections) { ID type = section.getName(); ID solver_id = section.getParameter("name", type); auto tss_type = getOptionToType<TimeStepSolverType>(type); auto tss_options = this->getDefaultSolverOptions(tss_type); auto sub_solvers_sect = section.getSubSections(ParserType::_non_linear_solver); auto nb_non_linear_solver_section = section.getNbSubSections(ParserType::_non_linear_solver); auto nls_type = tss_options.non_linear_solver_type; if (nb_non_linear_solver_section == 1) { auto && nls_section = *(sub_solvers_sect.first); nls_type = getOptionToType<NonLinearSolverType>(nls_section.getName()); } else if (nb_non_linear_solver_section > 0) { AKANTU_EXCEPTION("More than one non linear solver are provided for the " "time step solver " << solver_id); } this->getNewSolver(solver_id, tss_type, nls_type); if (nb_non_linear_solver_section == 1) { const auto & nls_section = *(sub_solvers_sect.first); this->dof_manager->getNonLinearSolver(solver_id).parseSection( nls_section); } auto sub_integrator_sections = section.getSubSections(ParserType::_integration_scheme); for (auto && is_section : sub_integrator_sections) { const auto & dof_type_str = is_section.getName(); ID dof_id; try { ID tmp = is_section.getParameter("name"); dof_id = tmp; } catch (...) { AKANTU_EXCEPTION("No degree of freedom name specified for the " "integration scheme of type " << dof_type_str); } auto it_type = getOptionToType<IntegrationSchemeType>(dof_type_str); IntegrationScheme::SolutionType s_type = is_section.getParameter( "solution_type", tss_options.solution_type[dof_id]); this->setIntegrationScheme(solver_id, dof_id, it_type, s_type); } for (auto & is_type : tss_options.integration_scheme_type) { if (!this->hasIntegrationScheme(solver_id, is_type.first)) { this->setIntegrationScheme(solver_id, is_type.first, is_type.second, tss_options.solution_type[is_type.first]); } } } if (section.hasParameter("default_solver")) { ID default_solver = section.getParameter("default_solver"); if (this->hasSolver(default_solver)) { this->setDefaultSolver(default_solver); } else AKANTU_EXCEPTION( "The solver \"" << default_solver << "\" was not created, it cannot be set as default solver"); } } /* -------------------------------------------------------------------------- */ TimeStepSolver & ModelSolver::getSolver(const ID & solver_id) { ID tmp_solver_id = solver_id; if (tmp_solver_id == "") tmp_solver_id = this->default_solver_id; TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(tmp_solver_id); return tss; } /* -------------------------------------------------------------------------- */ const TimeStepSolver & ModelSolver::getSolver(const ID & solver_id) const { ID tmp_solver_id = solver_id; if (solver_id == "") tmp_solver_id = this->default_solver_id; const TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(tmp_solver_id); return tss; } /* -------------------------------------------------------------------------- */ TimeStepSolver & ModelSolver::getTimeStepSolver(const ID & solver_id) { return this->getSolver(solver_id); } /* -------------------------------------------------------------------------- */ const TimeStepSolver & ModelSolver::getTimeStepSolver(const ID & solver_id) const { return this->getSolver(solver_id); } /* -------------------------------------------------------------------------- */ NonLinearSolver & ModelSolver::getNonLinearSolver(const ID & solver_id) { return this->getSolver(solver_id).getNonLinearSolver(); } /* -------------------------------------------------------------------------- */ const NonLinearSolver & ModelSolver::getNonLinearSolver(const ID & solver_id) const { return this->getSolver(solver_id).getNonLinearSolver(); } /* -------------------------------------------------------------------------- */ bool ModelSolver::hasSolver(const ID & solver_id) const { ID tmp_solver_id = solver_id; if (solver_id == "") tmp_solver_id = this->default_solver_id; if (not this->dof_manager) { AKANTU_EXCEPTION("No DOF manager was initialized"); } return this->dof_manager->hasTimeStepSolver(tmp_solver_id); } /* -------------------------------------------------------------------------- */ void ModelSolver::setDefaultSolver(const ID & solver_id) { AKANTU_DEBUG_ASSERT( this->hasSolver(solver_id), "Cannot set the default solver to a solver that does not exists"); this->default_solver_id = solver_id; } /* -------------------------------------------------------------------------- */ void ModelSolver::solveStep(const ID & solver_id) { AKANTU_DEBUG_IN(); TimeStepSolver & tss = this->getSolver(solver_id); // make one non linear solve tss.solveStep(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ModelSolver::getNewSolver(const ID & solver_id, TimeStepSolverType time_step_solver_type, NonLinearSolverType non_linear_solver_type) { if (this->default_solver_id == "") { this->default_solver_id = solver_id; } if (non_linear_solver_type == _nls_auto) { switch (time_step_solver_type) { case _tsst_dynamic: case _tsst_static: non_linear_solver_type = _nls_newton_raphson; break; case _tsst_dynamic_lumped: non_linear_solver_type = _nls_lumped; break; case _tsst_not_defined: AKANTU_EXCEPTION(time_step_solver_type << " is not a valid time step solver type"); break; } } this->initSolver(time_step_solver_type, non_linear_solver_type); NonLinearSolver & nls = this->dof_manager->getNewNonLinearSolver( solver_id, non_linear_solver_type); this->dof_manager->getNewTimeStepSolver(solver_id, time_step_solver_type, nls); } /* -------------------------------------------------------------------------- */ Real ModelSolver::getTimeStep(const ID & solver_id) const { const TimeStepSolver & tss = this->getSolver(solver_id); return tss.getTimeStep(); } /* -------------------------------------------------------------------------- */ void ModelSolver::setTimeStep(Real time_step, const ID & solver_id) { TimeStepSolver & tss = this->getSolver(solver_id); return tss.setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ void ModelSolver::setIntegrationScheme( const ID & solver_id, const ID & dof_id, const IntegrationSchemeType & integration_scheme_type, IntegrationScheme::SolutionType solution_type) { TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(solver_id); tss.setIntegrationScheme(dof_id, integration_scheme_type, solution_type); } /* -------------------------------------------------------------------------- */ bool ModelSolver::hasDefaultSolver() const { return (this->default_solver_id != ""); } /* -------------------------------------------------------------------------- */ bool ModelSolver::hasIntegrationScheme(const ID & solver_id, const ID & dof_id) const { TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(solver_id); return tss.hasIntegrationScheme(dof_id); } /* -------------------------------------------------------------------------- */ void ModelSolver::predictor() {} /* -------------------------------------------------------------------------- */ void ModelSolver::corrector() {} /* -------------------------------------------------------------------------- */ TimeStepSolverType ModelSolver::getDefaultSolverType() const { return _tsst_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions ModelSolver::getDefaultSolverOptions(__attribute__((unused)) const TimeStepSolverType & type) const { ModelSolverOptions options; options.non_linear_solver_type = _nls_auto; return options; } } // namespace akantu diff --git a/src/model/model_solver.hh b/src/model/model_solver.hh index 4c6179ad9..7b2c61c21 100644 --- a/src/model/model_solver.hh +++ b/src/model/model_solver.hh @@ -1,193 +1,194 @@ /** * @file model_solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Jul 22 10:53:10 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Class regrouping the common solve interface to the different models * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "integration_scheme.hh" #include "parsable.hh" #include "solver_callback.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MODEL_SOLVER_HH__ #define __AKANTU_MODEL_SOLVER_HH__ namespace akantu { class Mesh; class DOFManager; class TimeStepSolver; class NonLinearSolver; struct ModelSolverOptions; } namespace akantu { class ModelSolver : public Parsable, public SolverCallback, public SynchronizerRegistry { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ModelSolver(Mesh & mesh, const ModelType & type, const ID & id, UInt memory_id); ~ModelSolver() override; /// initialize the dof manager based on solver type passed in the input file void initDOFManager(); /// initialize the dof manager based on the used chosen solver type void initDOFManager(const ID & solver_type); protected: /// initialize the dof manager based on the used chosen solver type void initDOFManager(const ParserSection & section, const ID & solver_type); /// Callback for the model to instantiate the matricees when needed virtual void initSolver(TimeStepSolverType /*time_step_solver_type*/, NonLinearSolverType /*non_linear_solver_type*/) {} /// get the section in the input file (if it exsits) corresponding to this /// model std::tuple<ParserSection, bool> getParserSection(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// solve a step using a given pre instantiated time step solver and /// nondynamic linear solver virtual void solveStep(const ID & solver_id = ""); /// Initialize a time solver that can be used afterwards with its id void getNewSolver(const ID & solver_id, TimeStepSolverType time_step_solver_type, NonLinearSolverType non_linear_solver_type = _nls_auto); /// set an integration scheme for a given dof and a given solver void setIntegrationScheme(const ID & solver_id, const ID & dof_id, const IntegrationSchemeType & integration_scheme_type, IntegrationScheme::SolutionType solution_type = IntegrationScheme::_not_defined); /// set an externally instantiated integration scheme void setIntegrationScheme(const ID & solver_id, const ID & dof_id, IntegrationScheme & integration_scheme, IntegrationScheme::SolutionType solution_type = IntegrationScheme::_not_defined); /* ------------------------------------------------------------------------ */ /* SolverCallback interface */ /* ------------------------------------------------------------------------ */ public: /// Predictor interface for the callback void predictor() override; /// Corrector interface for the callback void corrector() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Default time step solver to instantiate for this model virtual TimeStepSolverType getDefaultSolverType() const; /// Default configurations for a given time step solver virtual ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const; /// get access to the internal dof manager DOFManager & getDOFManager() { return *this->dof_manager; } /// get the time step of a given solver Real getTimeStep(const ID & solver_id = "") const; /// set the time step of a given solver virtual void setTimeStep(Real time_step, const ID & solver_id = ""); /// set the parameter 'param' of the solver 'solver_id' // template <typename T> // void set(const ID & param, const T & value, const ID & solver_id = ""); /// get the parameter 'param' of the solver 'solver_id' // const Parameter & get(const ID & param, const ID & solver_id = "") const; /// answer to the question "does the solver exists ?" bool hasSolver(const ID & solver_id) const; /// changes the current default solver void setDefaultSolver(const ID & solver_id); /// is a default solver defined bool hasDefaultSolver() const; /// is an integration scheme set for a given solver and a given dof bool hasIntegrationScheme(const ID & solver_id, const ID & dof_id) const; TimeStepSolver & getTimeStepSolver(const ID & solver_id = ""); NonLinearSolver & getNonLinearSolver(const ID & solver_id = ""); const TimeStepSolver & getTimeStepSolver(const ID & solver_id = "") const; const NonLinearSolver & getNonLinearSolver(const ID & solver_id = "") const; private: TimeStepSolver & getSolver(const ID & solver_id); const TimeStepSolver & getSolver(const ID & solver_id) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: ModelType model_type; private: ID parent_id; UInt parent_memory_id; /// Underlying mesh Mesh & mesh; /// Underlying dof_manager (the brain...) std::unique_ptr<DOFManager> dof_manager; /// Default time step solver to use ID default_solver_id; }; struct ModelSolverOptions { NonLinearSolverType non_linear_solver_type; std::map<ID, IntegrationSchemeType> integration_scheme_type; std::map<ID, IntegrationScheme::SolutionType> solution_type; }; } // akantu #endif /* __AKANTU_MODEL_SOLVER_HH__ */ diff --git a/src/model/non_linear_solver.cc b/src/model/non_linear_solver.cc index a6333d41e..0fcf58024 100644 --- a/src/model/non_linear_solver.cc +++ b/src/model/non_linear_solver.cc @@ -1,78 +1,79 @@ /** * @file non_linear_solver.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Oct 13 15:34:43 2015 + * @date creation: Tue Jul 20 2010 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of the base class NonLinearSolver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver.hh" #include "dof_manager.hh" #include "solver_callback.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolver::NonLinearSolver( DOFManager & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : Memory(id, memory_id), Parsable(ParserType::_non_linear_solver, id), _dof_manager(dof_manager), non_linear_solver_type(non_linear_solver_type) { this->registerParam("type", this->non_linear_solver_type, _pat_parsable, "Non linear solver type"); } /* -------------------------------------------------------------------------- */ NonLinearSolver::~NonLinearSolver() = default; /* -------------------------------------------------------------------------- */ void NonLinearSolver::checkIfTypeIsSupported() { if (this->supported_type.find(this->non_linear_solver_type) == this->supported_type.end()) { AKANTU_EXCEPTION("The resolution method " << this->non_linear_solver_type << " is not implemented in the non linear solver " << this->id << "!"); } } /* -------------------------------------------------------------------------- */ void NonLinearSolver::assembleResidual(SolverCallback & solver_callback) { if (solver_callback.canSplitResidual() and non_linear_solver_type == _nls_linear) { this->_dof_manager.clearResidual(); solver_callback.assembleResidual("external"); this->_dof_manager.assembleMatMulDOFsToResidual("K", -1.); solver_callback.assembleResidual("inertial"); } else { solver_callback.assembleResidual(); } } } // akantu diff --git a/src/model/non_linear_solver.hh b/src/model/non_linear_solver.hh index 2cea85168..ef6d5a624 100644 --- a/src/model/non_linear_solver.hh +++ b/src/model/non_linear_solver.hh @@ -1,98 +1,99 @@ /** * @file non_linear_solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Aug 24 23:48:41 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Feb 21 2018 * * @brief Non linear solver interface * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LINEAR_SOLVER_HH__ #define __AKANTU_NON_LINEAR_SOLVER_HH__ namespace akantu { class DOFManager; class SolverCallback; } namespace akantu { class NonLinearSolver : private Memory, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLinearSolver(DOFManager & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id = "non_linear_solver", UInt memory_id = 0); ~NonLinearSolver() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// solve the system described by the jacobian matrix, and rhs contained in /// the dof manager virtual void solve(SolverCallback & callback) = 0; protected: void checkIfTypeIsSupported(); void assembleResidual(SolverCallback & callback); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: DOFManager & _dof_manager; /// type of non linear solver NonLinearSolverType non_linear_solver_type; /// list of supported non linear solver types std::set<NonLinearSolverType> supported_type; }; namespace debug { class NLSNotConvergedException : public Exception { public: NLSNotConvergedException(Real threshold, UInt niter, Real error) : Exception("The non linear solver did not converge."), threshold(threshold), niter(niter), error(error) {} Real threshold; UInt niter; Real error; }; } } // akantu #endif /* __AKANTU_NON_LINEAR_SOLVER_HH__ */ diff --git a/src/model/non_linear_solver_callback.hh b/src/model/non_linear_solver_callback.hh index 43895ca8e..45fe7cddd 100644 --- a/src/model/non_linear_solver_callback.hh +++ b/src/model/non_linear_solver_callback.hh @@ -1,60 +1,61 @@ /** * @file non_linear_solver_callback.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Sep 28 18:48:21 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Tue Feb 20 2018 * * @brief Interface to implement for the non linear solver to work * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LINEAR_SOLVER_CALLBACK_HH__ #define __AKANTU_NON_LINEAR_SOLVER_CALLBACK_HH__ namespace akantu { class NonLinearSolverCallback { /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// callback to assemble the Jacobian Matrix virtual void assembleJacobian() { AKANTU_TO_IMPLEMENT(); } /// callback to assemble the residual (rhs) virtual void assembleResidual() { AKANTU_TO_IMPLEMENT(); } /* ------------------------------------------------------------------------ */ /* Dynamic simulations part */ /* ------------------------------------------------------------------------ */ /// callback for the predictor (in case of dynamic simulation) virtual void predictor() { AKANTU_TO_IMPLEMENT(); } /// callback for the corrector (in case of dynamic simulation) virtual void corrector() { AKANTU_TO_IMPLEMENT(); } }; } // akantu #endif /* __AKANTU_NON_LINEAR_SOLVER_CALLBACK_HH__ */ diff --git a/src/model/non_linear_solver_default.hh b/src/model/non_linear_solver_default.hh index 3f7dad3e2..7cc1f2b53 100644 --- a/src/model/non_linear_solver_default.hh +++ b/src/model/non_linear_solver_default.hh @@ -1,44 +1,45 @@ /** * @file non_linear_solver_default.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Feb 16 10:37:01 2016 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Include for the default non linear solvers * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LINEAR_SOLVER_DEFAULT_HH__ #define __AKANTU_NON_LINEAR_SOLVER_DEFAULT_HH__ #if defined(AKANTU_IMPLICIT) #include "non_linear_solver_linear.hh" #include "non_linear_solver_newton_raphson.hh" #endif #include "non_linear_solver_lumped.hh" #endif /* __AKANTU_NON_LINEAR_SOLVER_DEFAULT_HH__ */ diff --git a/src/model/non_linear_solver_linear.cc b/src/model/non_linear_solver_linear.cc index 4a5704d52..6530cc27d 100644 --- a/src/model/non_linear_solver_linear.cc +++ b/src/model/non_linear_solver_linear.cc @@ -1,73 +1,74 @@ /** * @file non_linear_solver_linear.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 25 00:57:00 2015 + * @date creation: Tue Jul 20 2010 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of the default NonLinearSolver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver_linear.hh" #include "dof_manager_default.hh" #include "solver_callback.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolverLinear::NonLinearSolverLinear( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id), dof_manager(dof_manager), solver(dof_manager, "J", id + ":sparse_solver", memory_id) { this->supported_type.insert(_nls_linear); this->checkIfTypeIsSupported(); } /* -------------------------------------------------------------------------- */ NonLinearSolverLinear::~NonLinearSolverLinear() = default; /* ------------------------------------------------------------------------ */ void NonLinearSolverLinear::solve(SolverCallback & solver_callback) { this->dof_manager.updateGlobalBlockedDofs(); solver_callback.predictor(); solver_callback.assembleMatrix("J"); // Residual computed after J to allow the model to use K to compute the // residual this->assembleResidual(solver_callback); this->solver.solve(); solver_callback.corrector(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/non_linear_solver_linear.hh b/src/model/non_linear_solver_linear.hh index d402ec16e..155fb8246 100644 --- a/src/model/non_linear_solver_linear.hh +++ b/src/model/non_linear_solver_linear.hh @@ -1,78 +1,80 @@ /** * @file non_linear_solver_linear.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 25 00:48:07 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * - * @brief Default implementation of NonLinearSolver, in case no external library + * @brief Default implementation of NonLinearSolver, in case no external + * library * is there to do the job * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver.hh" #include "sparse_solver_mumps.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LINEAR_SOLVER_LINEAR_HH__ #define __AKANTU_NON_LINEAR_SOLVER_LINEAR_HH__ namespace akantu { class DOFManagerDefault; } namespace akantu { class NonLinearSolverLinear : public NonLinearSolver { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLinearSolverLinear(DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id = "non_linear_solver_linear", UInt memory_id = 0); ~NonLinearSolverLinear() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Function that solve the non linear system described by the dof manager and /// the solver callback functions void solve(SolverCallback & solver_callback) override; AKANTU_GET_MACRO_NOT_CONST(Solver, solver, SparseSolverMumps &); AKANTU_GET_MACRO(Solver, solver, const SparseSolverMumps &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: DOFManagerDefault & dof_manager; /// Sparse solver used for the linear solves SparseSolverMumps solver; }; } // akantu #endif /* __AKANTU_NON_LINEAR_SOLVER_LINEAR_HH__ */ diff --git a/src/model/non_linear_solver_lumped.cc b/src/model/non_linear_solver_lumped.cc index 1b0f70487..69e3e3a0f 100644 --- a/src/model/non_linear_solver_lumped.cc +++ b/src/model/non_linear_solver_lumped.cc @@ -1,102 +1,103 @@ /** * @file non_linear_solver_lumped.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 25 00:57:00 2015 + * @date creation: Tue Feb 16 2016 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of the default NonLinearSolver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver_lumped.hh" #include "communicator.hh" #include "dof_manager_default.hh" #include "solver_callback.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolverLumped::NonLinearSolverLumped( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id), dof_manager(dof_manager) { this->supported_type.insert(_nls_lumped); this->checkIfTypeIsSupported(); this->registerParam("b_a2x", this->alpha, 1., _pat_parsmod, "Conversion coefficient between x and A^{-1} b"); } /* -------------------------------------------------------------------------- */ NonLinearSolverLumped::~NonLinearSolverLumped() = default; /* ------------------------------------------------------------------------ */ void NonLinearSolverLumped::solve(SolverCallback & solver_callback) { this->dof_manager.updateGlobalBlockedDofs(); solver_callback.predictor(); auto & x = this->dof_manager.getGlobalSolution(); const auto & b = this->dof_manager.getResidual(); x.resize(b.size()); this->dof_manager.updateGlobalBlockedDofs(); const Array<bool> & blocked_dofs = this->dof_manager.getGlobalBlockedDOFs(); solver_callback.assembleResidual(); const auto & A = this->dof_manager.getLumpedMatrix("M"); // alpha is the conversion factor from from force/mass to acceleration needed // in model coupled with atomistic \todo find a way to define alpha per dof // type this->solveLumped(A, x, b, blocked_dofs, alpha); this->dof_manager.splitSolutionPerDOFs(); solver_callback.corrector(); } /* -------------------------------------------------------------------------- */ void NonLinearSolverLumped::solveLumped(const Array<Real> & A, Array<Real> & x, const Array<Real> & b, const Array<bool> & blocked_dofs, Real alpha) { auto A_it = A.begin(); auto x_it = x.begin(); auto x_end = x.end(); auto b_it = b.begin(); auto blocked_it = blocked_dofs.begin(); for (; x_it != x_end; ++x_it, ++b_it, ++A_it, ++blocked_it) { if (!(*blocked_it)) { *x_it = alpha * (*b_it / *A_it); } } } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/non_linear_solver_lumped.hh b/src/model/non_linear_solver_lumped.hh index b27623579..8241391b0 100644 --- a/src/model/non_linear_solver_lumped.hh +++ b/src/model/non_linear_solver_lumped.hh @@ -1,79 +1,81 @@ /** * @file non_linear_solver_lumped.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 25 00:48:07 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * - * @brief Default implementation of NonLinearSolver, in case no external library + * @brief Default implementation of NonLinearSolver, in case no external + * library * is there to do the job * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LINEAR_SOLVER_LUMPED_HH__ #define __AKANTU_NON_LINEAR_SOLVER_LUMPED_HH__ namespace akantu { class DOFManagerDefault; } namespace akantu { class NonLinearSolverLumped : public NonLinearSolver { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLinearSolverLumped(DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id = "non_linear_solver_lumped", UInt memory_id = 0); ~NonLinearSolverLumped() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Function that solve the non linear system described by the dof manager and /// the solver callback functions void solve(SolverCallback & solver_callback) override; static void solveLumped(const Array<Real> & A, Array<Real> & x, const Array<Real> & b, const Array<bool> & blocked_dofs, Real alpha); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: DOFManagerDefault & dof_manager; /// Coefficient to apply between x and A^{-1} b Real alpha; }; } // akantu #endif /* __AKANTU_NON_LINEAR_SOLVER_LUMPED_HH__ */ diff --git a/src/model/non_linear_solver_newton_raphson.cc b/src/model/non_linear_solver_newton_raphson.cc index 540ac8dd0..67618fff6 100644 --- a/src/model/non_linear_solver_newton_raphson.cc +++ b/src/model/non_linear_solver_newton_raphson.cc @@ -1,191 +1,192 @@ /** * @file non_linear_solver_newton_raphson.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 25 00:57:00 2015 + * @date creation: Tue Sep 15 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of the default NonLinearSolver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver_newton_raphson.hh" #include "communicator.hh" #include "dof_manager_default.hh" #include "solver_callback.hh" #include "sparse_solver_mumps.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolverNewtonRaphson::NonLinearSolverNewtonRaphson( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id), dof_manager(dof_manager), solver(std::make_unique<SparseSolverMumps>( dof_manager, "J", id + ":sparse_solver", memory_id)) { this->supported_type.insert(_nls_newton_raphson_modified); this->supported_type.insert(_nls_newton_raphson); this->supported_type.insert(_nls_linear); this->checkIfTypeIsSupported(); this->registerParam("threshold", convergence_criteria, 1e-10, _pat_parsmod, "Threshold to consider results as converged"); this->registerParam("convergence_type", convergence_criteria_type, _scc_solution, _pat_parsmod, "Type of convergence criteria"); this->registerParam("max_iterations", max_iterations, 10, _pat_parsmod, "Max number of iterations"); this->registerParam("error", error, _pat_readable, "Last reached error"); this->registerParam("nb_iterations", n_iter, _pat_readable, "Last reached number of iterations"); this->registerParam("converged", converged, _pat_readable, "Did last solve converged"); this->registerParam("force_linear_recompute", force_linear_recompute, true, _pat_modifiable, "Force reassembly of the jacobian matrix"); } /* -------------------------------------------------------------------------- */ NonLinearSolverNewtonRaphson::~NonLinearSolverNewtonRaphson() = default; /* ------------------------------------------------------------------------ */ void NonLinearSolverNewtonRaphson::solve(SolverCallback & solver_callback) { this->dof_manager.updateGlobalBlockedDofs(); solver_callback.predictor(); if (non_linear_solver_type == _nls_linear and solver_callback.canSplitResidual()) solver_callback.assembleMatrix("K"); this->assembleResidual(solver_callback); if (this->non_linear_solver_type == _nls_newton_raphson_modified || (this->non_linear_solver_type == _nls_linear && this->force_linear_recompute)) { solver_callback.assembleMatrix("J"); this->force_linear_recompute = false; } this->n_iter = 0; this->converged = false; if (this->convergence_criteria_type == _scc_residual) { this->converged = this->testConvergence(this->dof_manager.getResidual()); if (this->converged) return; } do { if (this->non_linear_solver_type == _nls_newton_raphson) solver_callback.assembleMatrix("J"); this->solver->solve(); solver_callback.corrector(); // EventManager::sendEvent(NonLinearSolver::AfterSparseSolve(method)); if (this->convergence_criteria_type == _scc_residual) { this->assembleResidual(solver_callback); this->converged = this->testConvergence(this->dof_manager.getResidual()); } else { this->converged = this->testConvergence(this->dof_manager.getGlobalSolution()); } if (this->convergence_criteria_type == _scc_solution and not this->converged) this->assembleResidual(solver_callback); // this->dump(); this->n_iter++; AKANTU_DEBUG_INFO( "[" << this->convergence_criteria_type << "] Convergence iteration " << std::setw(std::log10(this->max_iterations)) << this->n_iter << ": error " << this->error << (this->converged ? " < " : " > ") << this->convergence_criteria); } while (not this->converged and this->n_iter < this->max_iterations); // this makes sure that you have correct strains and stresses after the // solveStep function (e.g., for dumping) if (this->convergence_criteria_type == _scc_solution) this->assembleResidual(solver_callback); if (this->converged) { // this->sendEvent(NonLinearSolver::ConvergedEvent(method)); } else if (this->n_iter == this->max_iterations) { AKANTU_CUSTOM_EXCEPTION(debug::NLSNotConvergedException( this->convergence_criteria, this->n_iter, this->error)); AKANTU_DEBUG_WARNING("[" << this->convergence_criteria_type << "] Convergence not reached after " << std::setw(std::log10(this->max_iterations)) << this->n_iter << " iteration" << (this->n_iter == 1 ? "" : "s") << "!"); } return; } /* -------------------------------------------------------------------------- */ bool NonLinearSolverNewtonRaphson::testConvergence(const Array<Real> & array) { AKANTU_DEBUG_IN(); const Array<bool> & blocked_dofs = this->dof_manager.getGlobalBlockedDOFs(); UInt nb_degree_of_freedoms = array.size(); auto arr_it = array.begin(); auto bld_it = blocked_dofs.begin(); Real norm = 0.; for (UInt n = 0; n < nb_degree_of_freedoms; ++n, ++arr_it, ++bld_it) { bool is_local_node = this->dof_manager.isLocalOrMasterDOF(n); if ((!*bld_it) && is_local_node) { norm += *arr_it * *arr_it; } } dof_manager.getCommunicator().allReduce(norm, SynchronizerOperation::_sum); norm = std::sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something went wrong in the solve phase"); this->error = norm; return (error < this->convergence_criteria); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/non_linear_solver_newton_raphson.hh b/src/model/non_linear_solver_newton_raphson.hh index aff6ee6b8..f55719533 100644 --- a/src/model/non_linear_solver_newton_raphson.hh +++ b/src/model/non_linear_solver_newton_raphson.hh @@ -1,104 +1,106 @@ /** * @file non_linear_solver_newton_raphson.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 25 00:48:07 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * - * @brief Default implementation of NonLinearSolver, in case no external library + * @brief Default implementation of NonLinearSolver, in case no external + * library * is there to do the job * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LINEAR_SOLVER_NEWTON_RAPHSON_HH__ #define __AKANTU_NON_LINEAR_SOLVER_NEWTON_RAPHSON_HH__ namespace akantu { class DOFManagerDefault; class SparseSolverMumps; } namespace akantu { class NonLinearSolverNewtonRaphson : public NonLinearSolver { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLinearSolverNewtonRaphson( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id = "non_linear_solver_newton_raphson", UInt memory_id = 0); ~NonLinearSolverNewtonRaphson() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Function that solve the non linear system described by the dof manager and /// the solver callback functions void solve(SolverCallback & solver_callback) override; AKANTU_GET_MACRO_NOT_CONST(Solver, *solver, SparseSolverMumps &); AKANTU_GET_MACRO(Solver, *solver, const SparseSolverMumps &); protected: /// test the convergence compare norm of array to convergence_criteria bool testConvergence(const Array<Real> & array); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: DOFManagerDefault & dof_manager; /// Sparse solver used for the linear solves std::unique_ptr<SparseSolverMumps> solver; /// Type of convergence criteria SolveConvergenceCriteria convergence_criteria_type; /// convergence threshold Real convergence_criteria; /// Max number of iterations int max_iterations; /// Number of iterations at last solve call int n_iter{0}; /// Convergence error at last solve call Real error{0.}; /// Did the last call to solve reached convergence bool converged{false}; /// Force a re-computation of the jacobian matrix bool force_linear_recompute{true}; }; } // akantu #endif /* __AKANTU_NON_LINEAR_SOLVER_NEWTON_RAPHSON_HH__ */ diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index d266c906c..638092d44 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1377 +1,1377 @@ /** * @file material.cc * + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jul 27 2010 - * @date last modification: Tue Nov 24 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of the common part of the material 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Memory(id, model.getMemoryID()), Parsable(ParserType::_material, id), is_init(false), fem(model.getFEEngine()), finite_deformation(false), name(""), model(model), spatial_dimension(this->model.getSpatialDimension()), element_filter("element_filter", id, this->memory_id), stress("stress", *this), eigengradu("eigen_grad_u", *this), gradu("grad_u", *this), green_strain("green_strain", *this), piola_kirchhoff_2("piola_kirchhoff_2", *this), potential_energy("potential_energy", *this), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse coordinates", *this), interpolation_points_matrices("interpolation points matrices", *this) { AKANTU_DEBUG_IN(); /// for each connectivity types allocate the element filer array of the /// material element_filter.initialize(model.getMesh(), _spatial_dimension = spatial_dimension); // model.getMesh().initElementTypeMapArray(element_filter, 1, // spatial_dimension, // false, _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Memory(id, model.getMemoryID()), Parsable(ParserType::_material, id), is_init(false), fem(fe_engine), finite_deformation(false), name(""), model(model), spatial_dimension(dim), element_filter("element_filter", id, this->memory_id), stress("stress", *this, dim, fe_engine, this->element_filter), eigengradu("eigen_grad_u", *this, dim, fe_engine, this->element_filter), gradu("gradu", *this, dim, fe_engine, this->element_filter), green_strain("green_strain", *this, dim, fe_engine, this->element_filter), piola_kirchhoff_2("piola_kirchhoff_2", *this, dim, fe_engine, this->element_filter), potential_energy("potential_energy", *this, dim, fe_engine, this->element_filter), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse_coordinates", *this, dim, fe_engine, this->element_filter), interpolation_points_matrices("interpolation points matrices", *this, dim, fe_engine, this->element_filter) { AKANTU_DEBUG_IN(); element_filter.initialize(mesh, _spatial_dimension = spatial_dimension); // mesh.initElementTypeMapArray(element_filter, 1, spatial_dimension, false, // _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::~Material() = default; /* -------------------------------------------------------------------------- */ void Material::initialize() { registerParam("rho", rho, Real(0.), _pat_parsable | _pat_modifiable, "Density"); registerParam("name", name, std::string(), _pat_parsable | _pat_readable); registerParam("finite_deformation", finite_deformation, false, _pat_parsable | _pat_readable, "Is finite deformation"); registerParam("inelastic_deformation", inelastic_deformation, false, _pat_internal, "Is inelastic deformation"); /// allocate gradu stress for local elements eigengradu.initialize(spatial_dimension * spatial_dimension); gradu.initialize(spatial_dimension * spatial_dimension); stress.initialize(spatial_dimension * spatial_dimension); potential_energy.initialize(1); this->model.registerEventHandler(*this); } /* -------------------------------------------------------------------------- */ void Material::initMaterial() { AKANTU_DEBUG_IN(); if (finite_deformation) { this->piola_kirchhoff_2.initialize(spatial_dimension * spatial_dimension); if (use_previous_stress) this->piola_kirchhoff_2.initializeHistory(); this->green_strain.initialize(spatial_dimension * spatial_dimension); } if (use_previous_stress) this->stress.initializeHistory(); if (use_previous_gradu) this->gradu.initializeHistory(); for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); is_init = true; updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { if (it->second->hasHistory()) it->second->saveCurrentValues(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the residual by assembling @f$\int_{e} \sigma_e \frac{\partial * \varphi}{\partial X} dX @f$ * * @param[in] displacements nodes displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ // void Material::updateResidual(GhostType ghost_type) { // AKANTU_DEBUG_IN(); // computeAllStresses(ghost_type); // assembleResidual(ghost_type); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); if (!finite_deformation) { auto & internal_force = const_cast<Array<Real> &>(model.getInternalForce()); // Mesh & mesh = fem.getMesh(); for (auto && type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by /// @f$\mathbf{B}^t \mathbf{\sigma}_q@f$ Array<Real> * sigma_dphi_dx = new Array<Real>(nb_element * nb_quadrature_points, size_of_shapes_derivatives, "sigma_x_dphi_/_dX"); fem.computeBtD(stress(type, ghost_type), *sigma_dphi_dx, type, ghost_type, elem_filter); /** * compute @f$\int \sigma * \frac{\partial \varphi}{\partial X}dX@f$ by * @f$ \sum_q \mathbf{B}^t * \mathbf{\sigma}_q \overline w_q J_q@f$ */ Array<Real> * int_sigma_dphi_dx = new Array<Real>(nb_element, nb_nodes_per_element * spatial_dimension, "int_sigma_x_dphi_/_dX"); fem.integrate(*sigma_dphi_dx, *int_sigma_dphi_dx, size_of_shapes_derivatives, type, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble model.getDOFManager().assembleElementalArrayLocalArray( *int_sigma_dphi_dx, internal_force, type, ghost_type, -1, elem_filter); delete int_sigma_dphi_dx; } } else { switch (spatial_dimension) { case 1: this->assembleInternalForces<1>(ghost_type); break; case 2: this->assembleInternalForces<2>(ghost_type); break; case 3: this->assembleInternalForces<3>(ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stress from the gradu * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (const auto & type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; Array<Real> & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, spatial_dimension, type, ghost_type, elem_filter); gradu_vect -= eigengradu(type, ghost_type); /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$ computeStress(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllCauchyStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(finite_deformation, "The Cauchy stress can only be " "computed if you are working in " "finite deformation."); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { switch (spatial_dimension) { case 1: this->computeCauchyStress<1>(type, ghost_type); break; case 2: this->computeCauchyStress<2>(type, ghost_type); break; case 3: this->computeCauchyStress<3>(type, ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::computeCauchyStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::matrix_iterator gradu_it = this->gradu(el_type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator gradu_end = this->gradu(el_type, ghost_type).end(dim, dim); Array<Real>::matrix_iterator piola_it = this->piola_kirchhoff_2(el_type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator stress_it = this->stress(el_type, ghost_type).begin(dim, dim); Matrix<Real> F_tensor(dim, dim); for (; gradu_it != gradu_end; ++gradu_it, ++piola_it, ++stress_it) { Matrix<Real> & grad_u = *gradu_it; Matrix<Real> & piola = *piola_it; Matrix<Real> & sigma = *stress_it; gradUToF<dim>(grad_u, F_tensor); this->computeCauchyStressOnQuad<dim>(F_tensor, piola, sigma); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::setToSteadyState(GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array<Real> & displacement = model.getDisplacement(); // resizeInternalArray(gradu); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); Array<Real> & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(displacement, gradu_vect, spatial_dimension, type, ghost_type, elem_filter); setToSteadyState(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stiffness matrix by assembling @f$\int_{\omega} B^t \times D * \times B d\omega @f$ * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { if (finite_deformation) { switch (spatial_dimension) { case 1: { assembleStiffnessMatrixNL<1>(type, ghost_type); assembleStiffnessMatrixL2<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrixNL<2>(type, ghost_type); assembleStiffnessMatrixL2<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrixNL<3>(type, ghost_type); assembleStiffnessMatrixL2<3>(type, ghost_type); break; } } } else { switch (spatial_dimension) { case 1: { assembleStiffnessMatrix<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrix<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrix<3>(type, ghost_type); break; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<UInt> & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) { AKANTU_DEBUG_OUT(); return; } // const Array<Real> & shapes_derivatives = // fem.getShapesDerivatives(type, ghost_type); Array<Real> & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array<Real> * tangent_stiffness_matrix = new Array<Real>(nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array<Real> * bt_d_b = new Array<Real>(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); fem.computeBtDB(*tangent_stiffness_matrix, *bt_d_b, 4, type, ghost_type, elem_filter); delete tangent_stiffness_matrix; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * K_e = new Array<Real>(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); // Array<Real> & gradu_vect = delta_gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); Array<Real> * shapes_derivatives_filtered = new Array<Real>( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); fem.filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_s_b_size = dim * nb_nodes_per_element; Array<Real> * bt_s_b = new Array<Real>(nb_element * nb_quadrature_points, bt_s_b_size * bt_s_b_size, "B^t*D*B"); UInt piola_matrix_size = getCauchyStressMatrixSize(dim); Matrix<Real> B(piola_matrix_size, bt_s_b_size); Matrix<Real> Bt_S(bt_s_b_size, piola_matrix_size); Matrix<Real> S(piola_matrix_size, piola_matrix_size); auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); auto Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size); auto Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size); auto piola_it = piola_kirchhoff_2(type, ghost_type).begin(dim, dim); for (; Bt_S_B_it != Bt_S_B_end; ++Bt_S_B_it, ++shapes_derivatives_filtered_it, ++piola_it) { auto & Bt_S_B = *Bt_S_B_it; const auto & Piola_kirchhoff_matrix = *piola_it; setCauchyStressMatrix<dim>(Piola_kirchhoff_matrix, S); VoigtHelper<dim>::transferBMatrixToBNL(*shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_S.template mul<true, false>(B, S); Bt_S_B.template mul<false, false>(Bt_S, B); } delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * K_e = new Array<Real>(nb_element, bt_s_b_size * bt_s_b_size, "K_e"); fem.integrate(*bt_s_b, *K_e, bt_s_b_size * bt_s_b_size, type, ghost_type, elem_filter); delete bt_s_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); Array<Real> & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array<Real> * tangent_stiffness_matrix = new Array<Real>(nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); Array<Real> * shapes_derivatives_filtered = new Array<Real>( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); fem.filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array<Real> * bt_d_b = new Array<Real>(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix<Real> B(tangent_size, dim * nb_nodes_per_element); Matrix<Real> B2(tangent_size, dim * nb_nodes_per_element); Matrix<Real> Bt_D(dim * nb_nodes_per_element, tangent_size); auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); auto Bt_D_B_it = bt_d_b->begin(bt_d_b_size, bt_d_b_size); auto grad_u_it = gradu_vect.begin(dim, dim); auto D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); auto D_end = tangent_stiffness_matrix->end(tangent_size, tangent_size); for (; D_it != D_end; ++D_it, ++Bt_D_B_it, ++shapes_derivatives_filtered_it, ++grad_u_it) { const auto & grad_u = *grad_u_it; const auto & D = *D_it; auto & Bt_D_B = *Bt_D_B_it; // transferBMatrixToBL1<dim > (*shapes_derivatives_filtered_it, B, // nb_nodes_per_element); VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); VoigtHelper<dim>::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2, nb_nodes_per_element); B += B2; Bt_D.template mul<true, false>(B, D); Bt_D_B.template mul<false, false>(Bt_D, B); } delete tangent_stiffness_matrix; delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * K_e = new Array<Real>(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real> & internal_force = model.getInternalForce(); Mesh & mesh = fem.getMesh(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); Array<Real> * shapesd_filtered = new Array<Real>( nb_element, size_of_shapes_derivatives, "filtered shapesd"); fem.filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); // Set stress vectors UInt stress_size = getTangentStiffnessVoigtSize(dim); // Set matrices B and BNL* UInt bt_s_size = dim * nb_nodes_per_element; auto * bt_s = new Array<Real>(nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); auto grad_u_it = this->gradu(type, ghost_type).begin(dim, dim); auto grad_u_end = this->gradu(type, ghost_type).end(dim, dim); auto stress_it = this->piola_kirchhoff_2(type, ghost_type).begin(dim, dim); shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator bt_s_it = bt_s->begin(bt_s_size, 1); Matrix<Real> S_vect(stress_size, 1); Matrix<Real> B_tensor(stress_size, bt_s_size); Matrix<Real> B2_tensor(stress_size, bt_s_size); for (; grad_u_it != grad_u_end; ++grad_u_it, ++stress_it, ++shapes_derivatives_filtered_it, ++bt_s_it) { auto & grad_u = *grad_u_it; auto & r_it = *bt_s_it; auto & S_it = *stress_it; setCauchyStressArray<dim>(S_it, S_vect); VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B_tensor, nb_nodes_per_element); VoigtHelper<dim>::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2_tensor, nb_nodes_per_element); B_tensor += B2_tensor; r_it.template mul<true, false>(B_tensor, S_vect); } delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * r_e = new Array<Real>(nb_element, bt_s_size, "r_e"); fem.integrate(*bt_s, *r_e, bt_s_size, type, ghost_type, elem_filter); delete bt_s; model.getDOFManager().assembleElementalArrayLocalArray( *r_e, internal_force, type, ghost_type, -1., elem_filter); delete r_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergyByElements() { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { computePotentialEnergy(type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergy(ElementType, GhostType) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real epot = 0.; computePotentialEnergyByElements(); /// integrate the potential energy for each type of elements for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { epot += fem.integrate(potential_energy(type, _not_ghost), type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy(ElementType & type, UInt index) { AKANTU_DEBUG_IN(); Real epot = 0.; Vector<Real> epot_on_quad_points(fem.getNbIntegrationPoints(type)); computePotentialEnergyByElement(type, index, epot_on_quad_points); epot = fem.integrate(epot_on_quad_points, type, element_filter(type)(index)); AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(const std::string & type) { AKANTU_DEBUG_IN(); if (type == "potential") return getPotentialEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(const std::string & energy_id, ElementType type, UInt index) { AKANTU_DEBUG_IN(); if (energy_id == "potential") return getPotentialEnergy(type, index); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ void Material::initElementalFieldInterpolation( const ElementTypeMapArray<Real> & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); this->fem.initElementalFieldInterpolationFromIntegrationPoints( interpolation_points_coordinates, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, &(this->element_filter)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(ElementTypeMapArray<Real> & result, const GhostType ghost_type) { this->fem.interpolateElementalFieldFromIntegrationPoints( this->stress, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, result, ghost_type, &(this->element_filter)); } /* -------------------------------------------------------------------------- */ void Material::interpolateStressOnFacets( ElementTypeMapArray<Real> & result, ElementTypeMapArray<Real> & by_elem_result, const GhostType ghost_type) { interpolateStress(by_elem_result, ghost_type); UInt stress_size = this->stress.getNbComponent(); const Mesh & mesh = this->model.getMesh(); const Mesh & mesh_facets = mesh.getMeshFacets(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_fil = element_filter(type, ghost_type); Array<Real> & by_elem_res = by_elem_result(type, ghost_type); UInt nb_element = elem_fil.size(); UInt nb_element_full = this->model.getMesh().getNbElement(type, ghost_type); UInt nb_interpolation_points_per_elem = by_elem_res.size() / nb_element_full; const Array<Element> & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); UInt nb_quad_per_facet = nb_interpolation_points_per_elem / nb_facet_per_elem; Element element_for_comparison{type, 0, ghost_type}; const Array<std::vector<Element>> * element_to_facet = nullptr; GhostType current_ghost_type = _casper; Array<Real> * result_vec = nullptr; Array<Real>::const_matrix_iterator result_it = by_elem_res.begin_reinterpret( stress_size, nb_interpolation_points_per_elem, nb_element_full); for (UInt el = 0; el < nb_element; ++el) { UInt global_el = elem_fil(el); element_for_comparison.element = global_el; for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element facet_elem = facet_to_element(global_el, f); UInt global_facet = facet_elem.element; if (facet_elem.ghost_type != current_ghost_type) { current_ghost_type = facet_elem.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( type_facet, current_ghost_type); result_vec = &result(type_facet, current_ghost_type); } bool is_second_element = (*element_to_facet)(global_facet)[0] != element_for_comparison; for (UInt q = 0; q < nb_quad_per_facet; ++q) { Vector<Real> result_local(result_vec->storage() + (global_facet * nb_quad_per_facet + q) * result_vec->getNbComponent() + is_second_element * stress_size, stress_size); const Matrix<Real> & result_tmp(result_it[global_el]); result_local = result_tmp(f * nb_quad_per_facet + q); } } } } } /* -------------------------------------------------------------------------- */ template <typename T> const Array<T> & Material::getArray(const ID & /*vect_id*/, const ElementType & /*type*/, const GhostType & /*ghost_type*/) const { AKANTU_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <typename T> Array<T> & Material::getArray(const ID & /*vect_id*/, const ElementType & /*type*/, const GhostType & /*ghost_type*/) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <> const Array<Real> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<Real>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << " (" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> Array<Real> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<Real>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << " (" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> const Array<UInt> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<UInt>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << " (" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> Array<UInt> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<UInt>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <typename T> const InternalField<T> & Material::getInternal(__attribute__((unused)) const ID & int_id) const { AKANTU_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T> & Material::getInternal(__attribute__((unused)) const ID & int_id) { AKANTU_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <> const InternalField<Real> & Material::getInternal(const ID & int_id) const { auto it = internal_vectors_real.find(getID() + ":" + int_id); if (it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> InternalField<Real> & Material::getInternal(const ID & int_id) { auto it = internal_vectors_real.find(getID() + ":" + int_id); if (it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> const InternalField<UInt> & Material::getInternal(const ID & int_id) const { auto it = internal_vectors_uint.find(getID() + ":" + int_id); if (it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> InternalField<UInt> & Material::getInternal(const ID & int_id) { auto it = internal_vectors_uint.find(getID() + ":" + int_id); if (it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ void Material::addElements(const Array<Element> & elements_to_add) { AKANTU_DEBUG_IN(); UInt mat_id = model.getInternalIndexFromID(getID()); Array<Element>::const_iterator<Element> el_begin = elements_to_add.begin(); Array<Element>::const_iterator<Element> el_end = elements_to_add.end(); for (; el_begin != el_end; ++el_begin) { const Element & element = *el_begin; Array<UInt> & mat_indexes = model.getMaterialByElement(element.type, element.ghost_type); Array<UInt> & mat_loc_num = model.getMaterialLocalNumbering(element.type, element.ghost_type); UInt index = this->addElement(element.type, element.element, element.ghost_type); mat_indexes(element.element) = mat_id; mat_loc_num(element.element) = index; } this->resizeInternals(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::removeElements(const Array<Element> & elements_to_remove) { AKANTU_DEBUG_IN(); Array<Element>::const_iterator<Element> el_begin = elements_to_remove.begin(); Array<Element>::const_iterator<Element> el_end = elements_to_remove.end(); if (el_begin == el_end) return; ElementTypeMapArray<UInt> material_local_new_numbering( "remove mat filter elem", getID(), getMemoryID()); Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; element.ghost_type = ghost_type; ElementTypeMapArray<UInt>::type_iterator it = element_filter.firstType(_all_dimensions, ghost_type, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = element_filter.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; element.type = type; Array<UInt> & elem_filter = this->element_filter(type, ghost_type); Array<UInt> & mat_loc_num = this->model.getMaterialLocalNumbering(type, ghost_type); if (!material_local_new_numbering.exists(type, ghost_type)) material_local_new_numbering.alloc(elem_filter.size(), 1, type, ghost_type); Array<UInt> & mat_renumbering = material_local_new_numbering(type, ghost_type); UInt nb_element = elem_filter.size(); Array<UInt> elem_filter_tmp; UInt new_id = 0; for (UInt el = 0; el < nb_element; ++el) { element.element = elem_filter(el); if (std::find(el_begin, el_end, element) == el_end) { elem_filter_tmp.push_back(element.element); mat_renumbering(el) = new_id; mat_loc_num(element.element) = new_id; ++new_id; } else { mat_renumbering(el) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.size()); elem_filter.copy(elem_filter_tmp); } } for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::resizeInternals() { AKANTU_DEBUG_IN(); for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::onElementsAdded(const Array<Element> &, const NewElementsEvent &) { this->resizeInternals(); } /* -------------------------------------------------------------------------- */ void Material::onElementsRemoved( const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { UInt my_num = model.getInternalIndexFromID(getID()); ElementTypeMapArray<UInt> material_local_new_numbering( "remove mat filter elem", getID(), getMemoryID()); auto el_begin = element_list.begin(); auto el_end = element_list.end(); for (auto && gt : ghost_types) { for (auto && type : new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) { if (not element_filter.exists(type, gt) || element_filter(type, gt).size() == 0) continue; auto & elem_filter = element_filter(type, gt); auto & mat_indexes = this->model.getMaterialByElement(type, gt); auto & mat_loc_num = this->model.getMaterialLocalNumbering(type, gt); auto nb_element = this->model.getMesh().getNbElement(type, gt); // all materials will resize of the same size... mat_indexes.resize(nb_element); mat_loc_num.resize(nb_element); if (!material_local_new_numbering.exists(type, gt)) material_local_new_numbering.alloc(elem_filter.size(), 1, type, gt); auto & mat_renumbering = material_local_new_numbering(type, gt); const auto & renumbering = new_numbering(type, gt); Array<UInt> elem_filter_tmp; UInt ni = 0; Element el{type, 0, gt}; for (UInt i = 0; i < elem_filter.size(); ++i) { el.element = elem_filter(i); if (std::find(el_begin, el_end, el) == el_end) { UInt new_el = renumbering(el.element); AKANTU_DEBUG_ASSERT(new_el != UInt(-1), "A not removed element as been badly renumbered"); elem_filter_tmp.push_back(new_el); mat_renumbering(i) = ni; mat_indexes(new_el) = my_num; mat_loc_num(new_el) = ni; ++ni; } else { mat_renumbering(i) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.size()); elem_filter.copy(elem_filter_tmp); } } for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); } /* -------------------------------------------------------------------------- */ void Material::beforeSolveStep() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::afterSolveStep() { for (auto & type : element_filter.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { this->updateEnergies(type, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDamageIteration() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::onDamageUpdate() { ElementTypeMapArray<UInt>::type_iterator it = this->element_filter.firstType( _all_dimensions, _not_ghost, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = element_filter.lastType(_all_dimensions, _not_ghost, _ek_not_defined); for (; it != end; ++it) { this->updateEnergiesAfterDamage(*it, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDump() { if (this->isFiniteDeformation()) this->computeAllCauchyStresses(_not_ghost); } /* -------------------------------------------------------------------------- */ void Material::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; std::string type = getID().substr(getID().find_last_of(':') + 1); stream << space << "Material " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /// extrapolate internal values void Material::extrapolateInternal(const ID & id, const Element & element, __attribute__((unused)) const Matrix<Real> & point, Matrix<Real> & extrapolated) { if (this->isInternal<Real>(id, element.kind())) { UInt nb_element = this->element_filter(element.type, element.ghost_type).size(); const ID name = this->getID() + ":" + id; UInt nb_quads = this->internal_vectors_real[name]->getFEEngine().getNbIntegrationPoints( element.type, element.ghost_type); const Array<Real> & internal = this->getArray<Real>(id, element.type, element.ghost_type); UInt nb_component = internal.getNbComponent(); Array<Real>::const_matrix_iterator internal_it = internal.begin_reinterpret(nb_component, nb_quads, nb_element); Element local_element = this->convertToLocalElement(element); /// instead of really extrapolating, here the value of the first GP /// is copied into the result vector. This works only for linear /// elements /// @todo extrapolate!!!! AKANTU_DEBUG_WARNING("This is a fix, values are not truly extrapolated"); const Matrix<Real> & values = internal_it[local_element.element]; UInt index = 0; Vector<Real> tmp(nb_component); for (UInt j = 0; j < values.cols(); ++j) { tmp = values(j); if (tmp.norm() > 0) { index = j; break; } } for (UInt i = 0; i < extrapolated.size(); ++i) { extrapolated(i) = values(index); } } else { Matrix<Real> default_values(extrapolated.rows(), extrapolated.cols(), 0.); extrapolated = default_values; } } /* -------------------------------------------------------------------------- */ void Material::applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u, const GhostType ghost_type) { for (auto && type : element_filter.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { if (!element_filter(type, ghost_type).size()) continue; auto eigen_it = this->eigengradu(type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto eigen_end = this->eigengradu(type, ghost_type) .end(spatial_dimension, spatial_dimension); for (; eigen_it != eigen_end; ++eigen_it) { auto & current_eigengradu = *eigen_it; current_eigengradu = prescribed_eigen_grad_u; } } } } // namespace akantu diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh index d66f49984..fae76952a 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,680 +1,679 @@ /** * @file material.hh * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Mother class for all materials * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "aka_voigthelper.hh" #include "data_accessor.hh" #include "integration_point.hh" #include "parsable.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ #include "internal_field.hh" #include "random_internal_field.hh" /* -------------------------------------------------------------------------- */ #include "mesh_events.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_HH__ #define __AKANTU_MATERIAL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Model; class SolidMechanicsModel; } // namespace akantu namespace akantu { /** * Interface of all materials * Prerequisites for a new material * - inherit from this class * - implement the following methods: * \code * virtual Real getStableTimeStep(Real h, const Element & element = * ElementNull); * * virtual void computeStress(ElementType el_type, * GhostType ghost_type = _not_ghost); * * virtual void computeTangentStiffness(const ElementType & el_type, * Array<Real> & tangent_matrix, * GhostType ghost_type = _not_ghost); * \endcode * */ class Material : public Memory, public DataAccessor<Element>, public Parsable, public MeshEventHandler, protected SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: #if __cplusplus > 199711L Material(const Material & mat) = delete; Material & operator=(const Material & mat) = delete; #endif /// Initialize material with defaults Material(SolidMechanicsModel & model, const ID & id = ""); /// Initialize material with custom mesh & fe_engine Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); /// Destructor ~Material() override; protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Function that materials can/should reimplement */ /* ------------------------------------------------------------------------ */ protected: /// constitutive law virtual void computeStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_TO_IMPLEMENT(); } /// compute the tangent stiffness matrix virtual void computeTangentModuli(__attribute__((unused)) const ElementType & el_type, __attribute__((unused)) Array<Real> & tangent_matrix, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_TO_IMPLEMENT(); } /// compute the potential energy virtual void computePotentialEnergy(ElementType el_type, GhostType ghost_type = _not_ghost); /// compute the potential energy for an element virtual void computePotentialEnergyByElement(__attribute__((unused)) ElementType type, __attribute__((unused)) UInt index, __attribute__((unused)) Vector<Real> & epot_on_quad_points) { AKANTU_TO_IMPLEMENT(); } virtual void updateEnergies(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} virtual void updateEnergiesAfterDamage(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} /// set the material to steady state (to be implemented for materials that /// need it) virtual void setToSteadyState(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} /// function called to update the internal parameters when the modifiable /// parameters are modified virtual void updateInternalParameters() {} public: /// extrapolate internal values virtual void extrapolateInternal(const ID & id, const Element & element, const Matrix<Real> & points, Matrix<Real> & extrapolated); /// compute the p-wave speed in the material virtual Real getPushWaveSpeed(__attribute__((unused)) const Element & element) const { AKANTU_TO_IMPLEMENT(); } /// compute the s-wave speed in the material virtual Real getShearWaveSpeed(__attribute__((unused)) const Element & element) const { AKANTU_TO_IMPLEMENT(); } /// get a material celerity to compute the stable time step (default: is the /// push wave speed) virtual Real getCelerity(const Element & element) const { return getPushWaveSpeed(element); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template <typename T> void registerInternal(__attribute__((unused)) InternalField<T> & vect) { AKANTU_TO_IMPLEMENT(); } template <typename T> void unregisterInternal(__attribute__((unused)) InternalField<T> & vect) { AKANTU_TO_IMPLEMENT(); } /// initialize the material computed parameter virtual void initMaterial(); /// compute the residual for this material // virtual void updateResidual(GhostType ghost_type = _not_ghost); /// assemble the residual for this material virtual void assembleInternalForces(GhostType ghost_type); /// save the stress in the previous_stress if needed virtual void savePreviousState(); /// compute the stresses for this material virtual void computeAllStresses(GhostType ghost_type = _not_ghost); // virtual void // computeAllStressesFromTangentModuli(GhostType ghost_type = _not_ghost); virtual void computeAllCauchyStresses(GhostType ghost_type = _not_ghost); /// set material to steady state void setToSteadyState(GhostType ghost_type = _not_ghost); /// compute the stiffness matrix virtual void assembleStiffnessMatrix(GhostType ghost_type); /// add an element to the local mesh filter inline UInt addElement(const ElementType & type, UInt element, const GhostType & ghost_type); inline UInt addElement(const Element & element); /// add many elements at once void addElements(const Array<Element> & elements_to_add); /// remove many element at once void removeElements(const Array<Element> & elements_to_remove); /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override; /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points */ void interpolateStress(ElementTypeMapArray<Real> & result, const GhostType ghost_type = _not_ghost); /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points and store the * results per facet */ void interpolateStressOnFacets(ElementTypeMapArray<Real> & result, ElementTypeMapArray<Real> & by_elem_result, const GhostType ghost_type = _not_ghost); /** * function to initialize the elemental field interpolation * function by inverting the quadrature points' coordinates */ void initElementalFieldInterpolation( const ElementTypeMapArray<Real> & interpolation_points_coordinates); /* ------------------------------------------------------------------------ */ /* Common part */ /* ------------------------------------------------------------------------ */ protected: /* ------------------------------------------------------------------------ */ inline UInt getTangentStiffnessVoigtSize(UInt spatial_dimension) const; /// compute the potential energy by element void computePotentialEnergyByElements(); /// resize the intenals arrays virtual void resizeInternals(); /* ------------------------------------------------------------------------ */ /* Finite deformation functions */ /* This functions area implementing what is described in the paper of Bathe */ /* et al, in IJNME, Finite Element Formulations For Large Deformation */ /* Dynamic Analysis, Vol 9, 353-386, 1975 */ /* ------------------------------------------------------------------------ */ protected: /// assemble the residual template <UInt dim> void assembleInternalForces(GhostType ghost_type); /// Computation of Cauchy stress tensor in the case of finite deformation from /// the 2nd Piola-Kirchhoff for a given element type template <UInt dim> void computeCauchyStress(ElementType el_type, GhostType ghost_type = _not_ghost); /// Computation the Cauchy stress the 2nd Piola-Kirchhoff and the deformation /// gradient template <UInt dim> inline void computeCauchyStressOnQuad(const Matrix<Real> & F, const Matrix<Real> & S, Matrix<Real> & cauchy, const Real & C33 = 1.0) const; template <UInt dim> void computeAllStressesFromTangentModuli(const ElementType & type, GhostType ghost_type); template <UInt dim> void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// assembling in finite deformation template <UInt dim> void assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type); template <UInt dim> void assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type); /// Size of the Stress matrix for the case of finite deformation see: Bathe et /// al, IJNME, Vol 9, 353-386, 1975 inline UInt getCauchyStressMatrixSize(UInt spatial_dimension) const; /// Sets the stress matrix according to Bathe et al, IJNME, Vol 9, 353-386, /// 1975 template <UInt dim> inline void setCauchyStressMatrix(const Matrix<Real> & S_t, Matrix<Real> & sigma); /// write the stress tensor in the Voigt notation. template <UInt dim> inline void setCauchyStressArray(const Matrix<Real> & S_t, Matrix<Real> & sigma_voight); /* ------------------------------------------------------------------------ */ /* Conversion functions */ /* ------------------------------------------------------------------------ */ public: template <UInt dim> static inline void gradUToF(const Matrix<Real> & grad_u, Matrix<Real> & F); static inline void rightCauchy(const Matrix<Real> & F, Matrix<Real> & C); static inline void leftCauchy(const Matrix<Real> & F, Matrix<Real> & B); template <UInt dim> static inline void gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon); template <UInt dim> static inline void gradUToGreenStrain(const Matrix<Real> & grad_u, Matrix<Real> & epsilon); static inline Real stressToVonMises(const Matrix<Real> & stress); protected: /// converts global element to local element inline Element convertToLocalElement(const Element & global_element) const; /// converts local element to global element inline Element convertToGlobalElement(const Element & local_element) const; /// converts global quadrature point to local quadrature point inline IntegrationPoint convertToLocalPoint(const IntegrationPoint & global_point) const; /// converts local quadrature point to global quadrature point inline IntegrationPoint convertToGlobalPoint(const IntegrationPoint & local_point) const; /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; template <typename T> inline void packElementDataHelper(const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id = ID()) const; template <typename T> inline void unpackElementDataHelper(ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id = ID()); /* ------------------------------------------------------------------------ */ /* MeshEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) override{}; void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, const RemovedNodesEvent &) override{}; void onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) override; void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; void onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) override{}; /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void beforeSolveStep(); virtual void afterSolveStep(); void onDamageIteration() override; void onDamageUpdate() override; void onDump() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Name, name, const std::string &); AKANTU_GET_MACRO(Model, model, const SolidMechanicsModel &) AKANTU_GET_MACRO(ID, Memory::getID(), const ID &); AKANTU_GET_MACRO(Rho, rho, Real); AKANTU_SET_MACRO(Rho, rho, Real); AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// return the potential energy for the subset of elements contained by the /// material Real getPotentialEnergy(); /// return the potential energy for the provided element Real getPotentialEnergy(ElementType & type, UInt index); /// return the energy (identified by id) for the subset of elements contained /// by the material virtual Real getEnergy(const std::string & energy_id); /// return the energy (identified by id) for the provided element virtual Real getEnergy(const std::string & energy_id, ElementType type, UInt index); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementFilter, element_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(GradU, gradu, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PotentialEnergy, potential_energy, Real); AKANTU_GET_MACRO(GradU, gradu, const ElementTypeMapArray<Real> &); AKANTU_GET_MACRO(Stress, stress, const ElementTypeMapArray<Real> &); AKANTU_GET_MACRO(ElementFilter, element_filter, const ElementTypeMapArray<UInt> &); AKANTU_GET_MACRO(FEEngine, fem, FEEngine &); bool isNonLocal() const { return is_non_local; } template <typename T> const Array<T> & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; template <typename T> Array<T> & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost); template <typename T> const InternalField<T> & getInternal(const ID & id) const; template <typename T> InternalField<T> & getInternal(const ID & id); template <typename T> inline bool isInternal(const ID & id, const ElementKind & element_kind) const; template <typename T> ElementTypeMap<UInt> getInternalDataPerElem(const ID & id, const ElementKind & element_kind) const; bool isFiniteDeformation() const { return finite_deformation; } bool isInelasticDeformation() const { return inelastic_deformation; } template <typename T> inline void setParam(const ID & param, T value); inline const Parameter & getParam(const ID & param) const; template <typename T> void flattenInternal(const std::string & field_id, ElementTypeMapArray<T> & internal_flat, const GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) const; /// apply a constant eigengrad_u everywhere in the material virtual void applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u, const GhostType = _not_ghost); /// specify if the matrix need to be recomputed for this material virtual bool hasStiffnessMatrixChanged() { return true; } protected: bool isInit() const { return is_init; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// boolean to know if the material has been initialized bool is_init; std::map<ID, InternalField<Real> *> internal_vectors_real; std::map<ID, InternalField<UInt> *> internal_vectors_uint; std::map<ID, InternalField<bool> *> internal_vectors_bool; protected: /// Link to the fem object in the model FEEngine & fem; /// Finite deformation bool finite_deformation; /// Finite deformation bool inelastic_deformation; /// material name std::string name; /// The model to witch the material belong SolidMechanicsModel & model; /// density : rho Real rho; /// spatial dimension UInt spatial_dimension; /// list of element handled by the material ElementTypeMapArray<UInt> element_filter; /// stresses arrays ordered by element types InternalField<Real> stress; /// eigengrad_u arrays ordered by element types InternalField<Real> eigengradu; /// grad_u arrays ordered by element types InternalField<Real> gradu; /// Green Lagrange strain (Finite deformation) InternalField<Real> green_strain; /// Second Piola-Kirchhoff stress tensor arrays ordered by element types /// (Finite deformation) InternalField<Real> piola_kirchhoff_2; /// potential energy by element InternalField<Real> potential_energy; /// tell if using in non local mode or not bool is_non_local; /// tell if the material need the previous stress state bool use_previous_stress; /// tell if the material need the previous strain state bool use_previous_gradu; /// elemental field interpolation coordinates InternalField<Real> interpolation_inverse_coordinates; /// elemental field interpolation points InternalField<Real> interpolation_points_matrices; /// vector that contains the names of all the internals that need to /// be transferred when material interfaces move std::vector<ID> internals_to_transfer; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Material & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "material_inline_impl.cc" #include "internal_field_tmpl.hh" #include "random_internal_field_tmpl.hh" /* -------------------------------------------------------------------------- */ /* Auto loop */ /* -------------------------------------------------------------------------- */ /// This can be used to automatically write the loop on quadrature points in /// functions such as computeStress. This macro in addition to write the loop /// provides two tensors (matrices) sigma and grad_u #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type) \ Array<Real>::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ Array<Real>::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type) \ .end(this->spatial_dimension, this->spatial_dimension); \ \ this->stress(el_type, ghost_type) \ .resize(this->gradu(el_type, ghost_type).size()); \ \ Array<Real>::iterator<Matrix<Real>> stress_it = \ this->stress(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ \ if (this->isFiniteDeformation()) { \ this->piola_kirchhoff_2(el_type, ghost_type) \ .resize(this->gradu(el_type, ghost_type).size()); \ stress_it = this->piola_kirchhoff_2(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ } \ \ for (; gradu_it != gradu_end; ++gradu_it, ++stress_it) { \ Matrix<Real> & __attribute__((unused)) grad_u = *gradu_it; \ Matrix<Real> & __attribute__((unused)) sigma = *stress_it #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END } /// This can be used to automatically write the loop on quadrature points in /// functions such as computeTangentModuli. This macro in addition to write the /// loop provides two tensors (matrices) sigma_tensor, grad_u, and a matrix /// where the elemental tangent moduli should be stored in Voigt Notation #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_mat) \ Array<Real>::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ Array<Real>::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type) \ .end(this->spatial_dimension, this->spatial_dimension); \ Array<Real>::matrix_iterator sigma_it = \ this->stress(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ \ tangent_mat.resize(this->gradu(el_type, ghost_type).size()); \ \ UInt tangent_size = \ this->getTangentStiffnessVoigtSize(this->spatial_dimension); \ Array<Real>::matrix_iterator tangent_it = \ tangent_mat.begin(tangent_size, tangent_size); \ \ for (; gradu_it != gradu_end; ++gradu_it, ++sigma_it, ++tangent_it) { \ Matrix<Real> & __attribute__((unused)) grad_u = *gradu_it; \ Matrix<Real> & __attribute__((unused)) sigma_tensor = *sigma_it; \ Matrix<Real> & tangent = *tangent_it #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END } /* -------------------------------------------------------------------------- */ namespace akantu { using MaterialFactory = Factory<Material, ID, UInt, const ID &, SolidMechanicsModel &, const ID &>; } // namespace akantu #define INSTANTIATE_MATERIAL_ONLY(mat_name) \ template class mat_name<1>; \ template class mat_name<2>; \ template class mat_name<3> #define MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name) \ [](UInt dim, const ID &, SolidMechanicsModel & model, \ const ID & id) -> std::unique_ptr<Material> { \ switch (dim) { \ case 1: \ return std::make_unique<mat_name<1>>(model, id); \ case 2: \ return std::make_unique<mat_name<2>>(model, id); \ case 3: \ return std::make_unique<mat_name<3>>(model, id); \ default: \ AKANTU_EXCEPTION("The dimension " \ << dim << "is not a valid dimension for the material " \ << #id); \ } \ } #define INSTANTIATE_MATERIAL(id, mat_name) \ INSTANTIATE_MATERIAL_ONLY(mat_name); \ static bool material_is_alocated_##id[[gnu::unused]] = \ MaterialFactory::getInstance().registerAllocator( \ #id, MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name)) #endif /* __AKANTU_MATERIAL_HH__ */ diff --git a/src/model/solid_mechanics/material_inline_impl.cc b/src/model/solid_mechanics/material_inline_impl.cc index 41f6de00b..19d753e5a 100644 --- a/src/model/solid_mechanics/material_inline_impl.cc +++ b/src/model/solid_mechanics/material_inline_impl.cc @@ -1,462 +1,461 @@ /** * @file material_inline_impl.cc * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jul 27 2010 - * @date last modification: Wed Nov 25 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of the inline functions of the class material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const ElementType & type, UInt element, const GhostType & ghost_type) { Array<UInt> & el_filter = this->element_filter(type, ghost_type); el_filter.push_back(element); return el_filter.size() - 1; } /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const Element & element) { return this->addElement(element.type, element.element, element.ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Material::getTangentStiffnessVoigtSize(UInt dim) const { return (dim * (dim - 1) / 2 + dim); } /* -------------------------------------------------------------------------- */ inline UInt Material::getCauchyStressMatrixSize(UInt dim) const { return (dim * dim); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToF(const Matrix<Real> & grad_u, Matrix<Real> & F) { AKANTU_DEBUG_ASSERT(F.size() >= grad_u.size() && grad_u.size() == dim * dim, "The dimension of the tensor F should be greater or " "equal to the dimension of the tensor grad_u."); F.eye(); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) F(i, j) += grad_u(i, j); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::computeCauchyStressOnQuad(const Matrix<Real> & F, const Matrix<Real> & piola, Matrix<Real> & sigma, const Real & C33) const { Real J = F.det() * sqrt(C33); Matrix<Real> F_S(dim, dim); F_S.mul<false, false>(F, piola); Real constant = J ? 1. / J : 0; sigma.mul<false, true>(F_S, F, constant); } /* -------------------------------------------------------------------------- */ inline void Material::rightCauchy(const Matrix<Real> & F, Matrix<Real> & C) { C.mul<true, false>(F, F); } /* -------------------------------------------------------------------------- */ inline void Material::leftCauchy(const Matrix<Real> & F, Matrix<Real> & B) { B.mul<false, true>(F, F); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) { for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) = 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToGreenStrain(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) { epsilon.mul<true, false>(grad_u, grad_u, .5); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) += 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ inline Real Material::stressToVonMises(const Matrix<Real> & stress) { // compute deviatoric stress UInt dim = stress.cols(); Matrix<Real> deviatoric_stress = Matrix<Real>::eye(dim, -1. * stress.trace() / 3.); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) deviatoric_stress(i, j) += stress(i, j); // return Von Mises stress return std::sqrt(3. * deviatoric_stress.doubleDot(deviatoric_stress) / 2.); } /* ---------------------------------------------------------------------------*/ template <UInt dim> inline void Material::setCauchyStressArray(const Matrix<Real> & S_t, Matrix<Real> & sigma_voight) { AKANTU_DEBUG_IN(); sigma_voight.clear(); // see Finite element formulations for large deformation dynamic analysis, // Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau /* * 1d: [ s11 ]' * 2d: [ s11 s22 s12 ]' * 3d: [ s11 s22 s33 s23 s13 s12 ] */ for (UInt i = 0; i < dim; ++i) // diagonal terms sigma_voight(i, 0) = S_t(i, i); for (UInt i = 1; i < dim; ++i) // term s12 in 2D and terms s23 s13 in 3D sigma_voight(dim + i - 1, 0) = S_t(dim - i - 1, dim - 1); for (UInt i = 2; i < dim; ++i) // term s13 in 3D sigma_voight(dim + i, 0) = S_t(0, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::setCauchyStressMatrix(const Matrix<Real> & S_t, Matrix<Real> & sigma) { AKANTU_DEBUG_IN(); sigma.clear(); /// see Finite ekement formulations for large deformation dynamic analysis, /// Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau for (UInt i = 0; i < dim; ++i) { for (UInt m = 0; m < dim; ++m) { for (UInt n = 0; n < dim; ++n) { sigma(i * dim + m, i * dim + n) = S_t(m, n); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline Element Material::convertToLocalElement(const Element & global_element) const { UInt ge = global_element.element; #ifndef AKANTU_NDEBUG UInt model_mat_index = this->model.getMaterialByElement( global_element.type, global_element.ghost_type)(ge); UInt mat_index = this->model.getMaterialIndex(this->name); AKANTU_DEBUG_ASSERT(model_mat_index == mat_index, "Conversion of a global element in a local element for " "the wrong material " << this->name << std::endl); #endif UInt le = this->model.getMaterialLocalNumbering( global_element.type, global_element.ghost_type)(ge); Element tmp_quad{global_element.type, le, global_element.ghost_type}; return tmp_quad; } /* -------------------------------------------------------------------------- */ inline Element Material::convertToGlobalElement(const Element & local_element) const { UInt le = local_element.element; UInt ge = this->element_filter(local_element.type, local_element.ghost_type)(le); Element tmp_quad{local_element.type, ge, local_element.ghost_type}; return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToLocalPoint(const IntegrationPoint & global_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(global_point.type); Element el = this->convertToLocalElement(static_cast<const Element &>(global_point)); IntegrationPoint tmp_quad(el, global_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToGlobalPoint(const IntegrationPoint & local_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(local_point.type); Element el = this->convertToGlobalElement(static_cast<const Element &>(local_point)); IntegrationPoint tmp_quad(el, local_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline UInt Material::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { return (this->isFiniteDeformation() ? 3 : 1) * spatial_dimension * spatial_dimension * sizeof(Real) * this->getModel().getNbIntegrationPoints(elements); } return 0; } /* -------------------------------------------------------------------------- */ inline void Material::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { packElementDataHelper(piola_kirchhoff_2, buffer, elements); packElementDataHelper(gradu, buffer, elements); } packElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline void Material::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { unpackElementDataHelper(piola_kirchhoff_2, buffer, elements); unpackElementDataHelper(gradu, buffer, elements); } unpackElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline const Parameter & Material::getParam(const ID & param) const { try { return get(param); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::setParam(const ID & param, T value) { try { set<T>(param, value); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } updateInternalParameters(); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::packElementDataHelper( const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id) const { DataAccessor::packElementalDataHelper<T>(data_to_pack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::unpackElementDataHelper( ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id) { DataAccessor::unpackElementalDataHelper<T>(data_to_unpack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template <> inline void Material::registerInternal<Real>(InternalField<Real> & vect) { internal_vectors_real[vect.getID()] = &vect; } template <> inline void Material::registerInternal<UInt>(InternalField<UInt> & vect) { internal_vectors_uint[vect.getID()] = &vect; } template <> inline void Material::registerInternal<bool>(InternalField<bool> & vect) { internal_vectors_bool[vect.getID()] = &vect; } /* -------------------------------------------------------------------------- */ template <> inline void Material::unregisterInternal<Real>(InternalField<Real> & vect) { internal_vectors_real.erase(vect.getID()); } template <> inline void Material::unregisterInternal<UInt>(InternalField<UInt> & vect) { internal_vectors_uint.erase(vect.getID()); } template <> inline void Material::unregisterInternal<bool>(InternalField<bool> & vect) { internal_vectors_bool.erase(vect.getID()); } /* -------------------------------------------------------------------------- */ template <typename T> inline bool Material::isInternal(__attribute__((unused)) const ID & id, __attribute__((unused)) const ElementKind & element_kind) const { AKANTU_TO_IMPLEMENT(); } template <> inline bool Material::isInternal<Real>(const ID & id, const ElementKind & element_kind) const { auto internal_array = internal_vectors_real.find(this->getID() + ":" + id); if (internal_array == internal_vectors_real.end() || internal_array->second->getElementKind() != element_kind) return false; return true; } /* -------------------------------------------------------------------------- */ template <typename T> inline ElementTypeMap<UInt> Material::getInternalDataPerElem(const ID & field_id, const ElementKind & element_kind) const { if (!this->template isInternal<T>(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField<T> & internal_field = this->template getInternal<T>(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); UInt nb_data_per_quad = internal_field.getNbComponent(); ElementTypeMap<UInt> res; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { using type_iterator = typename InternalField<T>::type_iterator; type_iterator tit = internal_field.firstType(*gt); type_iterator tend = internal_field.lastType(*gt); for (; tit != tend; ++tit) { UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(*tit, *gt); res(*tit, *gt) = nb_data_per_quad * nb_quadrature_points; } } return res; } /* -------------------------------------------------------------------------- */ template <typename T> void Material::flattenInternal(const std::string & field_id, ElementTypeMapArray<T> & internal_flat, const GhostType ghost_type, ElementKind element_kind) const { if (!this->template isInternal<T>(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField<T> & internal_field = this->template getInternal<T>(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); const Mesh & mesh = fe_engine.getMesh(); using type_iterator = typename InternalField<T>::filter_type_iterator; type_iterator tit = internal_field.filterFirstType(ghost_type); type_iterator tend = internal_field.filterLastType(ghost_type); for (; tit != tend; ++tit) { ElementType type = *tit; const Array<Real> & src_vect = internal_field(type, ghost_type); const Array<UInt> & filter = internal_field.getFilter(type, ghost_type); // total number of elements in the corresponding mesh UInt nb_element_dst = mesh.getNbElement(type, ghost_type); // number of element in the internal field UInt nb_element_src = filter.size(); // number of quadrature points per elem UInt nb_quad_per_elem = fe_engine.getNbIntegrationPoints(type); // number of data per quadrature point UInt nb_data_per_quad = internal_field.getNbComponent(); if (!internal_flat.exists(type, ghost_type)) { internal_flat.alloc(nb_element_dst * nb_quad_per_elem, nb_data_per_quad, type, ghost_type); } if (nb_element_src == 0) continue; // number of data per element UInt nb_data = nb_quad_per_elem * nb_data_per_quad; Array<Real> & dst_vect = internal_flat(type, ghost_type); dst_vect.resize(nb_element_dst * nb_quad_per_elem); Array<UInt>::const_scalar_iterator it = filter.begin(); Array<UInt>::const_scalar_iterator end = filter.end(); auto it_src = src_vect.begin_reinterpret(nb_data, nb_element_src); auto it_dst = dst_vect.begin_reinterpret(nb_data, nb_element_dst); for (; it != end; ++it, ++it_src) { it_dst[*it] = *it_src; } } } } // akantu #endif /* __AKANTU_MATERIAL_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/material_list.hh.in b/src/model/solid_mechanics/material_list.hh.in index bd556cd36..cd6ca5b68 100644 --- a/src/model/solid_mechanics/material_list.hh.in +++ b/src/model/solid_mechanics/material_list.hh.in @@ -1,51 +1,43 @@ /** * @file material_list.hh.in * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Thu Feb 21 2013 - * @date last modification: Sat Jul 18 2015 + * @date creation: Wed Sep 01 2010 + * @date last modification: Wed Feb 03 2016 * * @brief List of materials and all includes * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) - * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2014-2018 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 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. + * 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 <http://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public License along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_LIST_HH__ #define __AKANTU_MATERIAL_LIST_HH__ #include "aka_config.hh" /* -------------------------------------------------------------------------- */ /* Material includes */ /* -------------------------------------------------------------------------- */ @AKANTU_MATERIAL_INCLUDES@ /* -------------------------------------------------------------------------- */ /* Material list */ /* -------------------------------------------------------------------------- */ #define AKANTU_MATERIAL_LIST \ @AKANTU_MATERIAL_LISTS@ // leave an empty line after the list #endif /* __AKANTU_MATERIAL_LIST_HH__ */ diff --git a/src/model/solid_mechanics/material_selector.hh b/src/model/solid_mechanics/material_selector.hh index eb9d161b8..552274dc9 100644 --- a/src/model/solid_mechanics/material_selector.hh +++ b/src/model/solid_mechanics/material_selector.hh @@ -1,160 +1,161 @@ /** * @file material_selector.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Thu Dec 17 2015 + * @date last modification: Mon Dec 18 2017 * * @brief class describing how to choose a material for a given element * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "element.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include <memory> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_SELECTOR_HH__ #define __AKANTU_MATERIAL_SELECTOR_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class SolidMechanicsModel; /** * main class to assign same or different materials for different * elements */ class MaterialSelector : public std::enable_shared_from_this<MaterialSelector> { public: MaterialSelector() = default; virtual ~MaterialSelector() = default; virtual inline UInt operator()(const Element & element) { if (fallback_selector) return (*fallback_selector)(element); return fallback_value; } inline void setFallback(UInt f) { fallback_value = f; } inline void setFallback(const std::shared_ptr<MaterialSelector> & fallback_selector) { this->fallback_selector = fallback_selector; } inline void setFallback(MaterialSelector & fallback_selector) { this->fallback_selector = fallback_selector.shared_from_this(); } inline std::shared_ptr<MaterialSelector> & getFallbackSelector() { return this->fallback_selector; } inline UInt getFallbackValue() { return this->fallback_value; } protected: UInt fallback_value{0}; std::shared_ptr<MaterialSelector> fallback_selector; }; /* -------------------------------------------------------------------------- */ /** * class that assigns the first material to regular elements by default */ class DefaultMaterialSelector : public MaterialSelector { public: explicit DefaultMaterialSelector( const ElementTypeMapArray<UInt> & material_index) : material_index(material_index) {} UInt operator()(const Element & element) override { if (not material_index.exists(element.type, element.ghost_type)) return MaterialSelector::operator()(element); const auto & mat_indexes = material_index(element.type, element.ghost_type); if (element.element < mat_indexes.size()) { auto && tmp_mat = mat_indexes(element.element); if (tmp_mat != UInt(-1)) return tmp_mat; } return MaterialSelector::operator()(element); } private: const ElementTypeMapArray<UInt> & material_index; }; /* -------------------------------------------------------------------------- */ /** * Use elemental data to assign materials */ template <typename T> class ElementDataMaterialSelector : public MaterialSelector { public: ElementDataMaterialSelector(const ElementTypeMapArray<T> & element_data, const SolidMechanicsModel & model, UInt first_index = 1) : element_data(element_data), model(model), first_index(first_index) {} inline T elementData(const Element & element) { DebugLevel dbl = debug::getDebugLevel(); debug::setDebugLevel(dblError); T data = element_data(element.type, element.ghost_type)(element.element); debug::setDebugLevel(dbl); return data; } inline UInt operator()(const Element & element) override { return MaterialSelector::operator()(element); } protected: /// list of element with the specified data (i.e. tag value) const ElementTypeMapArray<T> & element_data; /// the model that the materials belong const SolidMechanicsModel & model; /// first material index: equal to 1 if none specified UInt first_index; }; /* -------------------------------------------------------------------------- */ /** * class to use mesh data information to assign different materials * where name is the tag value: tag_0, tag_1 */ template <typename T> class MeshDataMaterialSelector : public ElementDataMaterialSelector<T> { public: MeshDataMaterialSelector(const std::string & name, const SolidMechanicsModel & model, UInt first_index = 1); }; } // namespace akantu #endif /* __AKANTU_MATERIAL_SELECTOR_HH__ */ diff --git a/src/model/solid_mechanics/material_selector_tmpl.hh b/src/model/solid_mechanics/material_selector_tmpl.hh index 93fda1636..5c0a9b94b 100644 --- a/src/model/solid_mechanics/material_selector_tmpl.hh +++ b/src/model/solid_mechanics/material_selector_tmpl.hh @@ -1,73 +1,74 @@ /** * @file material_selector_tmpl.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Fri May 01 2015 + * @date last modification: Tue Nov 07 2017 * * @brief Implementation of the template MaterialSelector * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "material_selector.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_SELECTOR_TMPL_HH__ #define __AKANTU_MATERIAL_SELECTOR_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <> inline UInt ElementDataMaterialSelector<std::string>:: operator()(const Element & element) { try { std::string material_name = this->elementData(element); return model.getMaterialIndex(material_name); } catch (...) { return MaterialSelector::operator()(element); } } /* -------------------------------------------------------------------------- */ template <> inline UInt ElementDataMaterialSelector<UInt>:: operator()(const Element & element) { try { return this->elementData(element) - first_index; } catch (...) { return MaterialSelector::operator()(element); } } /* -------------------------------------------------------------------------- */ template <typename T> MeshDataMaterialSelector<T>::MeshDataMaterialSelector( const std::string & name, const SolidMechanicsModel & model, UInt first_index) : ElementDataMaterialSelector<T>(model.getMesh().getData<T>(name), model, first_index) {} } // namespace akantu #endif /* __AKANTU_MATERIAL_SELECTOR_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/materials/internal_field.hh b/src/model/solid_mechanics/materials/internal_field.hh index af8ae8eaa..54312dbeb 100644 --- a/src/model/solid_mechanics/materials/internal_field.hh +++ b/src/model/solid_mechanics/materials/internal_field.hh @@ -1,260 +1,259 @@ /** * @file internal_field.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Thu Feb 08 2018 * * @brief Material internal properties * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_type_map.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTERNAL_FIELD_HH__ #define __AKANTU_INTERNAL_FIELD_HH__ namespace akantu { class Material; class FEEngine; /** * class for the internal fields of materials * to store values for each quadrature */ template <typename T> class InternalField : public ElementTypeMapArray<T> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: InternalField(const ID & id, Material & material); ~InternalField() override; /// This constructor is only here to let cohesive elements compile InternalField(const ID & id, Material & material, FEEngine & fem, const ElementTypeMapArray<UInt> & element_filter); /// More general constructor InternalField(const ID & id, Material & material, UInt dim, FEEngine & fem, const ElementTypeMapArray<UInt> & element_filter); InternalField(const ID & id, const InternalField<T> & other); private: InternalField operator=(__attribute__((unused)) const InternalField & other){}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// function to reset the FEEngine for the internal field virtual void setFEEngine(FEEngine & fe_engine); /// function to reset the element kind for the internal virtual void setElementKind(ElementKind element_kind); /// initialize the field to a given number of component virtual void initialize(UInt nb_component); /// activate the history of this field virtual void initializeHistory(); /// resize the arrays and set the new element to 0 virtual void resize(); /// set the field to a given value v virtual void setDefaultValue(const T & v); /// reset all the fields to the default value virtual void reset(); /// save the current values in the history virtual void saveCurrentValues(); /// remove the quadrature points corresponding to suppressed elements virtual void removeIntegrationPoints(const ElementTypeMapArray<UInt> & new_numbering); /// print the content void printself(std::ostream & stream, int /*indent*/ = 0) const override; /// get the default value inline operator T() const; virtual FEEngine & getFEEngine() { return *fem; } virtual const FEEngine & getFEEngine() const { return *fem; } /// AKANTU_GET_MACRO(FEEngine, *fem, FEEngine &); protected: /// initialize the arrays in the ElementTypeMapArray<T> void internalInitialize(UInt nb_component); /// set the values for new internals virtual void setArrayValues(T * begin, T * end); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: using type_iterator = typename ElementTypeMapArray<T>::type_iterator; using filter_type_iterator = typename ElementTypeMapArray<UInt>::type_iterator; /// get the type iterator on all types contained in the internal field type_iterator firstType(const GhostType & ghost_type = _not_ghost) const { return ElementTypeMapArray<T>::firstType(this->spatial_dimension, ghost_type, this->element_kind); } /// get the type iterator on the last type contained in the internal field type_iterator lastType(const GhostType & ghost_type = _not_ghost) const { return ElementTypeMapArray<T>::lastType(this->spatial_dimension, ghost_type, this->element_kind); } /// get the type iterator on all types contained in the internal field filter_type_iterator filterFirstType(const GhostType & ghost_type = _not_ghost) const { return this->element_filter.firstType(this->spatial_dimension, ghost_type, this->element_kind); } /// get the type iterator on the last type contained in the internal field filter_type_iterator filterLastType(const GhostType & ghost_type = _not_ghost) const { return this->element_filter.lastType(this->spatial_dimension, ghost_type, this->element_kind); } /// get the array for a given type of the element_filter const Array<UInt> getFilter(const ElementType & type, const GhostType & ghost_type = _not_ghost) const { return this->element_filter(type, ghost_type); } /// get the Array corresponding to the type en ghost_type specified virtual Array<T> & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost) { return ElementTypeMapArray<T>::operator()(type, ghost_type); } virtual const Array<T> & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost) const { return ElementTypeMapArray<T>::operator()(type, ghost_type); } virtual Array<T> & previous(const ElementType & type, const GhostType & ghost_type = _not_ghost) { AKANTU_DEBUG_ASSERT(previous_values != nullptr, "The history of the internal " << this->getID() << " has not been activated"); return this->previous_values->operator()(type, ghost_type); } virtual const Array<T> & previous(const ElementType & type, const GhostType & ghost_type = _not_ghost) const { AKANTU_DEBUG_ASSERT(previous_values != nullptr, "The history of the internal " << this->getID() << " has not been activated"); return this->previous_values->operator()(type, ghost_type); } virtual InternalField<T> & previous() { AKANTU_DEBUG_ASSERT(previous_values != nullptr, "The history of the internal " << this->getID() << " has not been activated"); return *(this->previous_values); } virtual const InternalField<T> & previous() const { AKANTU_DEBUG_ASSERT(previous_values != nullptr, "The history of the internal " << this->getID() << " has not been activated"); return *(this->previous_values); } /// check if the history is used or not bool hasHistory() const { return (previous_values != nullptr); } /// get the kind treated by the internal const ElementKind & getElementKind() const { return element_kind; } /// return the number of components UInt getNbComponent() const { return nb_component; } /// return the spatial dimension corresponding to the internal element type /// loop filter UInt getSpatialDimension() const { return this->spatial_dimension; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the material for which this is an internal parameter Material & material; /// the fem containing the mesh and the element informations FEEngine * fem; /// Element filter if needed const ElementTypeMapArray<UInt> & element_filter; /// default value T default_value; /// spatial dimension of the element to consider UInt spatial_dimension; /// ElementKind of the element to consider ElementKind element_kind; /// Number of component of the internal field UInt nb_component; /// Is the field initialized bool is_init; /// previous values InternalField<T> * previous_values; }; /// standard output stream operator template <typename T> inline std::ostream & operator<<(std::ostream & stream, const InternalField<T> & _this) { _this.printself(stream); return stream; } } // akantu #endif /* __AKANTU_INTERNAL_FIELD_HH__ */ diff --git a/src/model/solid_mechanics/materials/internal_field_tmpl.hh b/src/model/solid_mechanics/materials/internal_field_tmpl.hh index 9f694541b..c6476bcb9 100644 --- a/src/model/solid_mechanics/materials/internal_field_tmpl.hh +++ b/src/model/solid_mechanics/materials/internal_field_tmpl.hh @@ -1,317 +1,317 @@ /** * @file internal_field_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Material internal properties * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTERNAL_FIELD_TMPL_HH__ #define __AKANTU_INTERNAL_FIELD_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T>::InternalField(const ID & id, Material & material) : ElementTypeMapArray<T>(id, material.getID(), material.getMemoryID()), material(material), fem(&(material.getModel().getFEEngine())), element_filter(material.getElementFilter()), default_value(T()), spatial_dimension(material.getModel().getSpatialDimension()), element_kind(_ek_regular), nb_component(0), is_init(false), previous_values(nullptr) {} /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T>::InternalField( const ID & id, Material & material, FEEngine & fem, const ElementTypeMapArray<UInt> & element_filter) : ElementTypeMapArray<T>(id, material.getID(), material.getMemoryID()), material(material), fem(&fem), element_filter(element_filter), default_value(T()), spatial_dimension(material.getSpatialDimension()), element_kind(_ek_regular), nb_component(0), is_init(false), previous_values(nullptr) {} /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T>::InternalField( const ID & id, Material & material, UInt dim, FEEngine & fem, const ElementTypeMapArray<UInt> & element_filter) : ElementTypeMapArray<T>(id, material.getID(), material.getMemoryID()), material(material), fem(&fem), element_filter(element_filter), default_value(T()), spatial_dimension(dim), element_kind(_ek_regular), nb_component(0), is_init(false), previous_values(nullptr) {} /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T>::InternalField(const ID & id, const InternalField<T> & other) : ElementTypeMapArray<T>(id, other.material.getID(), other.material.getMemoryID()), material(other.material), fem(other.fem), element_filter(other.element_filter), default_value(other.default_value), spatial_dimension(other.spatial_dimension), element_kind(other.element_kind), nb_component(other.nb_component), is_init(false), previous_values(nullptr) { AKANTU_DEBUG_ASSERT(other.is_init, "Cannot create a copy of a non initialized field"); this->internalInitialize(this->nb_component); } /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T>::~InternalField() { if (this->is_init) { this->material.unregisterInternal(*this); } delete previous_values; } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::setFEEngine(FEEngine & fe_engine) { this->fem = &fe_engine; } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::setElementKind(ElementKind element_kind) { this->element_kind = element_kind; } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::initialize(UInt nb_component) { internalInitialize(nb_component); } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::initializeHistory() { if (!previous_values) previous_values = new InternalField<T>("previous_" + this->getID(), *this); } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::resize() { if (!this->is_init) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { filter_type_iterator it = this->filterFirstType(*gt); filter_type_iterator end = this->filterLastType(*gt); for (; it != end; ++it) { UInt nb_element = this->element_filter(*it, *gt).size(); UInt nb_quadrature_points = this->fem->getNbIntegrationPoints(*it, *gt); UInt new_size = nb_element * nb_quadrature_points; UInt old_size = 0; Array<T> * vect = nullptr; if (this->exists(*it, *gt)) { vect = &(this->operator()(*it, *gt)); old_size = vect->size(); vect->resize(new_size); } else { vect = &(this->alloc(nb_element * nb_quadrature_points, nb_component, *it, *gt)); } this->setArrayValues(vect->storage() + old_size * vect->getNbComponent(), vect->storage() + new_size * vect->getNbComponent()); } } } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::setDefaultValue(const T & value) { this->default_value = value; this->reset(); } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::reset() { for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { type_iterator it = this->firstType(*gt); type_iterator end = this->lastType(*gt); for (; it != end; ++it) { Array<T> & vect = this->operator()(*it, *gt); vect.clear(); this->setArrayValues( vect.storage(), vect.storage() + vect.size() * vect.getNbComponent()); } } } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::internalInitialize(UInt nb_component) { if (!this->is_init) { this->nb_component = nb_component; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { filter_type_iterator it = this->filterFirstType(*gt); filter_type_iterator end = this->filterLastType(*gt); for (; it != end; ++it) { UInt nb_element = this->element_filter(*it, *gt).size(); UInt nb_quadrature_points = this->fem->getNbIntegrationPoints(*it, *gt); if (this->exists(*it, *gt)) this->operator()(*it, *gt).resize(nb_element * nb_quadrature_points); else this->alloc(nb_element * nb_quadrature_points, nb_component, *it, *gt); } } this->material.registerInternal(*this); this->is_init = true; } this->reset(); if (this->previous_values) this->previous_values->internalInitialize(nb_component); } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::setArrayValues(T * begin, T * end) { for (; begin < end; ++begin) *begin = this->default_value; } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::saveCurrentValues() { AKANTU_DEBUG_ASSERT(this->previous_values != nullptr, "The history of the internal " << this->getID() << " has not been activated"); if (!this->is_init) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { type_iterator it = this->firstType(*gt); type_iterator end = this->lastType(*gt); for (; it != end; ++it) { this->previous_values->operator()(*it, *gt).copy( this->operator()(*it, *gt)); } } } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::removeIntegrationPoints( const ElementTypeMapArray<UInt> & new_numbering) { for (auto ghost_type : ghost_types) { for (auto type : new_numbering.elementTypes(_all_dimensions, ghost_type, _ek_not_defined)) { if (not this->exists(type, ghost_type)) continue; Array<T> & vect = this->operator()(type, ghost_type); if (vect.size() == 0) continue; const Array<UInt> & renumbering = new_numbering(type, ghost_type); UInt nb_quad_per_elem = fem->getNbIntegrationPoints(type, ghost_type); UInt nb_component = vect.getNbComponent(); Array<T> tmp(renumbering.size() * nb_quad_per_elem, nb_component); AKANTU_DEBUG_ASSERT( tmp.size() == vect.size(), "Something strange append some mater was created from nowhere!!"); AKANTU_DEBUG_ASSERT( tmp.size() == vect.size(), "Something strange append some mater was created or disappeared in " << vect.getID() << "(" << vect.size() << "!=" << tmp.size() << ") " "!!"); UInt new_size = 0; for (UInt i = 0; i < renumbering.size(); ++i) { UInt new_i = renumbering(i); if (new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component * nb_quad_per_elem, vect.storage() + i * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem * sizeof(T)); ++new_size; } } tmp.resize(new_size * nb_quad_per_elem); vect.copy(tmp); } } } /* -------------------------------------------------------------------------- */ template <typename T> void InternalField<T>::printself(std::ostream & stream, int indent[[gnu::unused]]) const { stream << "InternalField [ " << this->getID(); #if !defined(AKANTU_NDEBUG) if (AKANTU_DEBUG_TEST(dblDump)) { stream << std::endl; ElementTypeMapArray<T>::printself(stream, indent + 3); } else { #endif stream << " {" << this->getData(_not_ghost).size() << " types - " << this->getData(_ghost).size() << " ghost types" << "}"; #if !defined(AKANTU_NDEBUG) } #endif stream << " ]"; } /* -------------------------------------------------------------------------- */ template <> inline void ParameterTyped<InternalField<Real>>::setAuto(const ParserParameter & in_param) { Parameter::setAuto(in_param); Real r = in_param; param.setDefaultValue(r); } /* -------------------------------------------------------------------------- */ template <typename T> inline InternalField<T>::operator T() const { return default_value; } } // akantu #endif /* __AKANTU_INTERNAL_FIELD_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_core_includes.hh b/src/model/solid_mechanics/materials/material_core_includes.hh index 5804db7da..a95a5b1a3 100644 --- a/src/model/solid_mechanics/materials/material_core_includes.hh +++ b/src/model/solid_mechanics/materials/material_core_includes.hh @@ -1,68 +1,68 @@ /** * @file material_core_includes.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Sat Jul 18 2015 + * @date last modification: Wed Feb 03 2016 * * @brief List of materials for core package * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_CORE_INCLUDES_HH__ #define __AKANTU_MATERIAL_CORE_INCLUDES_HH__ /* -------------------------------------------------------------------------- */ /* Material list */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_CMAKE_LIST_MATERIALS // elastic materials #include "material_elastic.hh" #include "material_elastic_linear_anisotropic.hh" #include "material_elastic_orthotropic.hh" #include "material_neohookean.hh" // visco-elastic materials #include "material_standard_linear_solid_deviatoric.hh" // damage laws #include "material_marigo.hh" #include "material_mazars.hh" // small-deformation plasticity #include "material_linear_isotropic_hardening.hh" #endif #define AKANTU_CORE_MATERIAL_LIST \ ((2, (elastic, MaterialElastic)))((2, (neohookean, MaterialNeohookean)))( \ (2, (elastic_orthotropic, MaterialElasticOrthotropic)))( \ (2, (elastic_anisotropic, MaterialElasticLinearAnisotropic)))( \ (2, (sls_deviatoric, MaterialStandardLinearSolidDeviatoric)))( \ (2, (marigo, MaterialMarigo)))((2, (mazars, MaterialMazars)))( \ (2, (plastic_linear_isotropic_hardening, \ MaterialLinearIsotropicHardening))) #endif /* __AKANTU_MATERIAL_CORE_INCLUDES_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_damage.hh b/src/model/solid_mechanics/materials/material_damage/material_damage.hh index fb72e1549..6cefe9796 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_damage.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_damage.hh @@ -1,113 +1,112 @@ /** * @file material_damage.hh * * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sat Jul 11 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Material isotropic elastic * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_elastic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_DAMAGE_HH__ #define __AKANTU_MATERIAL_DAMAGE_HH__ namespace akantu { template <UInt spatial_dimension, template <UInt> class Parent = MaterialElastic> class MaterialDamage : public Parent<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialDamage(SolidMechanicsModel & model, const ID & id = ""); ~MaterialDamage() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; /// compute the tangent stiffness matrix for an element type void computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost) override; bool hasStiffnessMatrixChanged() override { return true; } protected: /// update the dissipated energy, must be called after the stress have been /// computed void updateEnergies(ElementType el_type, GhostType ghost_type) override; /// compute the tangent stiffness matrix for a given quadrature point inline void computeTangentModuliOnQuad(Matrix<Real> & tangent, Real & dam); /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// give the dissipated energy for the time step Real getDissipatedEnergy() const; Real getEnergy(const std::string & type) override; Real getEnergy(const std::string & energy_id, ElementType type, UInt index) override { return Parent<spatial_dimension>::getEnergy(energy_id, type, index); }; AKANTU_GET_MACRO_NOT_CONST(Damage, damage, ElementTypeMapArray<Real> &); AKANTU_GET_MACRO(Damage, damage, const ElementTypeMapArray<Real> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real) /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// damage internal variable InternalField<Real> damage; /// dissipated energy InternalField<Real> dissipated_energy; /// contain the current value of @f$ \int_0^{\epsilon}\sigma(\omega)d\omega /// @f$ the dissipated energy InternalField<Real> int_sigma; }; } // namespace akantu #include "material_damage_tmpl.hh" #endif /* __AKANTU_MATERIAL_DAMAGE_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh b/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh index 707acab2a..f83923f3e 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh @@ -1,74 +1,73 @@ /** * @file material_damage_non_local.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Aug 23 2012 - * @date last modification: Wed Oct 21 2015 + * @date last modification: Mon Sep 11 2017 * * @brief interface for non local damage material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_non_local.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_DAMAGE_NON_LOCAL_HH__ #define __AKANTU_MATERIAL_DAMAGE_NON_LOCAL_HH__ namespace akantu { template <UInt dim, class MaterialDamageLocal> class MaterialDamageNonLocal : public MaterialNonLocal<dim, MaterialDamageLocal> { public: using MaterialParent = MaterialNonLocal<dim, MaterialDamageLocal>; MaterialDamageNonLocal(SolidMechanicsModel & model, const ID & id) : MaterialParent(model, id){}; protected: /* ------------------------------------------------------------------------ */ virtual void computeNonLocalStress(ElementType type, GhostType ghost_type = _not_ghost) = 0; /* ------------------------------------------------------------------------ */ void computeNonLocalStresses(GhostType ghost_type) override { AKANTU_DEBUG_IN(); for (auto type : this->element_filter.elementTypes(dim, ghost_type)) { auto & elem_filter = this->element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; computeNonLocalStress(type, ghost_type); } AKANTU_DEBUG_OUT(); } }; } // namespace akantu #endif /* __AKANTU_MATERIAL_DAMAGE_NON_LOCAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh b/src/model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh index 2876eb704..88e744546 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh @@ -1,181 +1,181 @@ /** * @file material_damage_tmpl.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> + * @author Marion Estelle Chambart <mchambart@stucky.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Specialization of the material class for the damage material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_damage.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension, template <UInt> class Parent> MaterialDamage<spatial_dimension, Parent>::MaterialDamage( SolidMechanicsModel & model, const ID & id) : Parent<spatial_dimension>(model, id), damage("damage", *this), dissipated_energy("damage dissipated energy", *this), int_sigma("integral of sigma", *this) { AKANTU_DEBUG_IN(); this->is_non_local = false; this->use_previous_stress = true; this->use_previous_gradu = true; this->damage.initialize(1); this->dissipated_energy.initialize(1); this->int_sigma.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension, template <UInt> class Parent> void MaterialDamage<spatial_dimension, Parent>::initMaterial() { AKANTU_DEBUG_IN(); Parent<spatial_dimension>::initMaterial(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the dissipated energy in each element by a trapezoidal approximation * of * @f$ Ed = \int_0^{\epsilon}\sigma(\omega)d\omega - * \frac{1}{2}\sigma:\epsilon@f$ */ template <UInt spatial_dimension, template <UInt> class Parent> void MaterialDamage<spatial_dimension, Parent>::updateEnergies( ElementType el_type, GhostType ghost_type) { Parent<spatial_dimension>::updateEnergies(el_type, ghost_type); this->computePotentialEnergy(el_type, ghost_type); Array<Real>::matrix_iterator epsilon_p = this->gradu.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator sigma_p = this->stress.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); Array<Real>::const_scalar_iterator epot = this->potential_energy(el_type, ghost_type).begin(); Array<Real>::scalar_iterator ints = this->int_sigma(el_type, ghost_type).begin(); Array<Real>::scalar_iterator ed = this->dissipated_energy(el_type, ghost_type).begin(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> delta_gradu_it(*gradu_it); delta_gradu_it -= *epsilon_p; Matrix<Real> sigma_h(sigma); sigma_h += *sigma_p; Real dint = .5 * sigma_h.doubleDot(delta_gradu_it); *ints += dint; *ed = *ints - *epot; ++epsilon_p; ++sigma_p; ++epot; ++ints; ++ed; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension, template <UInt> class Parent> void MaterialDamage<spatial_dimension, Parent>::computeTangentModuli( const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type) { AKANTU_DEBUG_IN(); Parent<spatial_dimension>::computeTangentModuli(el_type, tangent_matrix, ghost_type); Real * dam = this->damage(el_type, ghost_type).storage(); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); computeTangentModuliOnQuad(tangent, *dam); ++dam; MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension, template <UInt> class Parent> void MaterialDamage<spatial_dimension, Parent>::computeTangentModuliOnQuad( Matrix<Real> & tangent, Real & dam) { tangent *= (1 - dam); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension, template <UInt> class Parent> Real MaterialDamage<spatial_dimension, Parent>::getDissipatedEnergy() const { AKANTU_DEBUG_IN(); Real de = 0.; /// integrate the dissipated energy for each type of elements for (auto & type : this->element_filter.elementTypes(spatial_dimension, _not_ghost)) { de += this->fem.integrate(dissipated_energy(type, _not_ghost), type, _not_ghost, this->element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return de; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension, template <UInt> class Parent> Real MaterialDamage<spatial_dimension, Parent>::getEnergy( const std::string & type) { if (type == "dissipated") return getDissipatedEnergy(); else return Parent<spatial_dimension>::getEnergy(type); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_damage/material_marigo.cc b/src/model/solid_mechanics/materials/material_damage/material_marigo.cc index 83738f986..d29e96758 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_marigo.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_marigo.cc @@ -1,107 +1,106 @@ /** * @file material_marigo.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 08 2015 + * @date last modification: Sun Jul 09 2017 * * @brief Specialization of the material class for the marigo material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_marigo.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialMarigo<spatial_dimension>::MaterialMarigo(SolidMechanicsModel & model, const ID & id) : MaterialDamage<spatial_dimension>(model, id), Yd("Yd", *this), damage_in_y(false), yc_limit(false) { AKANTU_DEBUG_IN(); this->registerParam("Sd", Sd, Real(5000.), _pat_parsable | _pat_modifiable); this->registerParam("epsilon_c", epsilon_c, Real(0.), _pat_parsable, "Critical strain"); this->registerParam("Yc limit", yc_limit, false, _pat_internal, "As the material a critical Y"); this->registerParam("damage_in_y", damage_in_y, false, _pat_parsable, "Use threshold (1-D)Y"); this->registerParam("Yd", Yd, _pat_parsable, "Damaging energy threshold"); this->Yd.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMarigo<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialDamage<spatial_dimension>::initMaterial(); updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMarigo<spatial_dimension>::updateInternalParameters() { MaterialDamage<spatial_dimension>::updateInternalParameters(); Yc = .5 * epsilon_c * this->E * epsilon_c; if (std::abs(epsilon_c) > std::numeric_limits<Real>::epsilon()) yc_limit = true; else yc_limit = false; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMarigo<spatial_dimension>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::scalar_iterator dam = this->damage(el_type, ghost_type).begin(); Array<Real>::scalar_iterator Yd_q = this->Yd(el_type, ghost_type).begin(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Real Y = 0.; computeStressOnQuad(grad_u, sigma, *dam, Y, *Yd_q); ++dam; ++Yd_q; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } INSTANTIATE_MATERIAL(marigo, MaterialMarigo); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_damage/material_marigo.hh b/src/model/solid_mechanics/materials/material_damage/material_marigo.hh index 39cb01c1e..3f5b63277 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_marigo.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_marigo.hh @@ -1,124 +1,123 @@ /** * @file material_marigo.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief Marigo damage law * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "material_damage.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_MARIGO_HH__ #define __AKANTU_MATERIAL_MARIGO_HH__ namespace akantu { /** * Material marigo * * parameters in the material files : * - Yd : (default: 50) * - Sd : (default: 5000) * - Ydrandomness : (default:0) */ template <UInt spatial_dimension> class MaterialMarigo : public MaterialDamage<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialMarigo(SolidMechanicsModel & model, const ID & id = ""); ~MaterialMarigo() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; void updateInternalParameters() override; /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; protected: /// constitutive law for a given quadrature point inline void computeStressOnQuad(Matrix<Real> & grad_u, Matrix<Real> & sigma, Real & dam, Real & Y, Real & Ydq); inline void computeDamageAndStressOnQuad(Matrix<Real> & sigma, Real & dam, Real & Y, Real & Ydq); /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// resistance to damage RandomInternalField<Real> Yd; /// damage threshold Real Sd; /// critical epsilon when the material is considered as broken Real epsilon_c; Real Yc; bool damage_in_y; bool yc_limit; }; } // akantu #include "material_marigo_inline_impl.cc" #endif /* __AKANTU_MATERIAL_MARIGO_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc b/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc index a0df92944..1288d566f 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc @@ -1,132 +1,131 @@ /** * @file material_marigo_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 04 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Fri Dec 02 2016 * * @brief Implementation of the inline functions of the material marigo * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_marigo.hh" #ifndef __AKANTU_MATERIAL_MARIGO_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_MARIGO_INLINE_IMPL_CC__ namespace akantu { template <UInt spatial_dimension> inline void MaterialMarigo<spatial_dimension>::computeStressOnQuad( Matrix<Real> & grad_u, Matrix<Real> & sigma, Real & dam, Real & Y, Real & Ydq) { MaterialElastic<spatial_dimension>::computeStressOnQuad(grad_u, sigma); Y = 0; for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { Y += sigma(i, j) * (grad_u(i, j) + grad_u(j, i)) / 2.; } } Y *= 0.5; if (damage_in_y) Y *= (1 - dam); if (yc_limit) Y = std::min(Y, Yc); if (!this->is_non_local) { computeDamageAndStressOnQuad(sigma, dam, Y, Ydq); } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialMarigo<spatial_dimension>::computeDamageAndStressOnQuad( Matrix<Real> & sigma, Real & dam, Real & Y, Real & Ydq) { Real Fd = Y - Ydq - Sd * dam; if (Fd > 0) dam = (Y - Ydq) / Sd; dam = std::min(dam, Real(1.)); sigma *= 1 - dam; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline UInt MaterialMarigo<spatial_dimension>::getNbData( const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if (tag == _gst_smm_init_mat) { size += sizeof(Real) * this->getModel().getNbIntegrationPoints(elements); } size += MaterialDamage<spatial_dimension>::getNbData(elements, tag); AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialMarigo<spatial_dimension>::packData( CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); if (tag == _gst_smm_init_mat) { this->packElementDataHelper(Yd, buffer, elements); } MaterialDamage<spatial_dimension>::packData(buffer, elements, tag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialMarigo<spatial_dimension>::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (tag == _gst_smm_init_mat) { this->unpackElementDataHelper(Yd, buffer, elements); } MaterialDamage<spatial_dimension>::unpackData(buffer, elements, tag); AKANTU_DEBUG_OUT(); } } // akantu #endif /* __AKANTU_MATERIAL_MARIGO_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.cc b/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.cc index 6eb060efe..731d6e099 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.cc @@ -1,106 +1,106 @@ /** * @file material_marigo_non_local.cc * + * @author Marion Estelle Chambart <mchambart@stucky.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Mon Sep 11 2017 * * @brief Marigo non-local inline function implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_marigo_non_local.hh" #include "non_local_neighborhood_base.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialMarigoNonLocal<spatial_dimension>::MaterialMarigoNonLocal( SolidMechanicsModel & model, const ID & id) : MaterialMarigoNonLocalParent(model, id), Y("Y", *this), Ynl("Y non local", *this) { AKANTU_DEBUG_IN(); this->is_non_local = true; this->Y.initialize(1); this->Ynl.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMarigoNonLocal<spatial_dimension>::registerNonLocalVariables() { this->model.getNonLocalManager().registerNonLocalVariable(this->Y.getName(), Ynl.getName(), 1); this->model.getNonLocalManager() .getNeighborhood(this->name) .registerNonLocalVariable(Ynl.getName()); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMarigoNonLocal<spatial_dimension>::computeStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real * dam = this->damage(el_type, ghost_type).storage(); Real * Yt = this->Y(el_type, ghost_type).storage(); Real * Ydq = this->Yd(el_type, ghost_type).storage(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); MaterialMarigo<spatial_dimension>::computeStressOnQuad(grad_u, sigma, *dam, *Yt, *Ydq); ++dam; ++Yt; ++Ydq; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMarigoNonLocal<spatial_dimension>::computeNonLocalStress( ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real * dam = this->damage(type, ghost_type).storage(); Real * Ydq = this->Yd(type, ghost_type).storage(); Real * Ynlt = this->Ynl(type, ghost_type).storage(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(type, ghost_type); this->computeDamageAndStressOnQuad(sigma, *dam, *Ynlt, *Ydq); ++dam; ++Ynlt; ++Ydq; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } INSTANTIATE_MATERIAL(marigo_non_local, MaterialMarigoNonLocal); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.hh b/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.hh index b9085cdf5..7b563afa8 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_marigo_non_local.hh @@ -1,94 +1,93 @@ /** * @file material_marigo_non_local.hh * * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Marigo non-local description * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_damage_non_local.hh" #include "material_marigo.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_MARIGO_NON_LOCAL_HH__ #define __AKANTU_MATERIAL_MARIGO_NON_LOCAL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /** * Material Marigo * * parameters in the material files : */ template <UInt spatial_dimension> class MaterialMarigoNonLocal : public MaterialDamageNonLocal<spatial_dimension, MaterialMarigo<spatial_dimension>> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef MaterialDamageNonLocal<spatial_dimension, MaterialMarigo<spatial_dimension>> MaterialMarigoNonLocalParent; MaterialMarigoNonLocal(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: void registerNonLocalVariables() override; /// constitutive law void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; void computeNonLocalStress(ElementType type, GhostType ghost_type = _not_ghost) override; private: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Y, Y, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: InternalField<Real> Y; InternalField<Real> Ynl; }; } // namespace akantu #endif /* __AKANTU_MATERIAL_MARIGO_NON_LOCAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_mazars.cc b/src/model/solid_mechanics/materials/material_damage/material_mazars.cc index fdba78438..7ada50bc7 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_mazars.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_mazars.cc @@ -1,82 +1,81 @@ /** * @file material_mazars.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Sun Jul 09 2017 * * @brief Specialization of the material class for the damage material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_mazars.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialMazars<spatial_dimension>::MaterialMazars(SolidMechanicsModel & model, const ID & id) : MaterialDamage<spatial_dimension>(model, id), K0("K0", *this), damage_in_compute_stress(true) { AKANTU_DEBUG_IN(); this->registerParam("K0", K0, _pat_parsable, "K0"); this->registerParam("At", At, Real(0.8), _pat_parsable, "At"); this->registerParam("Ac", Ac, Real(1.4), _pat_parsable, "Ac"); this->registerParam("Bc", Bc, Real(1900.), _pat_parsable, "Bc"); this->registerParam("Bt", Bt, Real(12000.), _pat_parsable, "Bt"); this->registerParam("beta", beta, Real(1.06), _pat_parsable, "beta"); this->K0.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMazars<spatial_dimension>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real * dam = this->damage(el_type, ghost_type).storage(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Real Ehat = 0; computeStressOnQuad(grad_u, sigma, *dam, Ehat); ++dam; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(mazars, MaterialMazars); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_damage/material_mazars.hh b/src/model/solid_mechanics/materials/material_damage/material_mazars.hh index 40d5d4358..01a4f7ab6 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_mazars.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_mazars.hh @@ -1,125 +1,125 @@ /** * @file material_mazars.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> + * @author Marion Estelle Chambart <mchambart@stucky.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief Material Following the Mazars law for damage evolution * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "material_damage.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_MAZARS_HH__ #define __AKANTU_MATERIAL_MAZARS_HH__ namespace akantu { /** * Material Mazars * * parameters in the material files : * - rho : density (default: 0) * - E : Young's modulus (default: 0) * - nu : Poisson's ratio (default: 1/2) * - K0 : Damage threshold * - At : Parameter damage traction 1 * - Bt : Parameter damage traction 2 * - Ac : Parameter damage compression 1 * - Bc : Parameter damage compression 2 * - beta : Parameter for shear */ template <UInt spatial_dimension> class MaterialMazars : public MaterialDamage<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialMazars(SolidMechanicsModel & model, const ID & id = ""); ~MaterialMazars() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; protected: /// constitutive law for a given quadrature point inline void computeStressOnQuad(const Matrix<Real> & grad_u, Matrix<Real> & sigma, Real & damage, Real & Ehat); inline void computeDamageAndStressOnQuad(const Matrix<Real> & grad_u, Matrix<Real> & sigma, Real & damage, Real & Ehat); inline void computeDamageOnQuad(const Real & epsilon_equ, const Matrix<Real> & sigma, const Vector<Real> & epsilon_princ, Real & dam); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// damage threshold RandomInternalField<Real> K0; /// parameter damage traction 1 Real At; /// parameter damage traction 2 Real Bt; /// parameter damage compression 1 Real Ac; /// parameter damage compression 2 Real Bc; /// parameter for shear Real beta; /// specify the variable to average false = ehat, true = damage (only valid /// for non local version) bool damage_in_compute_stress; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_mazars_inline_impl.cc" } // namespace akantu #endif /* __AKANTU_MATERIAL_MAZARS_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc b/src/model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc index 74150eb04..40eadf218 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc @@ -1,155 +1,155 @@ /** * @file material_mazars_inline_impl.cc * + * @author Marion Estelle Chambart <mchambart@stucky.ch> * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Apr 06 2011 - * @date last modification: Tue Aug 04 2015 + * @date last modification: Wed Feb 03 2016 * * @brief Implementation of the inline functions of the material damage * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialMazars<spatial_dimension>::computeStressOnQuad( const Matrix<Real> & grad_u, Matrix<Real> & sigma, Real & dam, Real & Ehat) { Matrix<Real> epsilon(3, 3); epsilon.clear(); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) epsilon(i, j) = .5 * (grad_u(i, j) + grad_u(j, i)); Vector<Real> Fdiag(3); Math::matrixEig(3, epsilon.storage(), Fdiag.storage()); Ehat = 0.; for (UInt i = 0; i < 3; ++i) { Real epsilon_p = std::max(Real(0.), Fdiag(i)); Ehat += epsilon_p * epsilon_p; } Ehat = sqrt(Ehat); MaterialElastic<spatial_dimension>::computeStressOnQuad(grad_u, sigma); if (damage_in_compute_stress) { computeDamageOnQuad(Ehat, sigma, Fdiag, dam); } if (!this->is_non_local) { computeDamageAndStressOnQuad(grad_u, sigma, dam, Ehat); } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialMazars<spatial_dimension>::computeDamageAndStressOnQuad( const Matrix<Real> & grad_u, Matrix<Real> & sigma, Real & dam, Real & Ehat) { if (!damage_in_compute_stress) { Vector<Real> Fdiag(3); Fdiag.clear(); Matrix<Real> epsilon(3, 3); epsilon.clear(); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) epsilon(i, j) = .5 * (grad_u(i, j) + grad_u(j, i)); Math::matrixEig(3, epsilon.storage(), Fdiag.storage()); computeDamageOnQuad(Ehat, sigma, Fdiag, dam); } sigma *= 1 - dam; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialMazars<spatial_dimension>::computeDamageOnQuad( const Real & epsilon_equ, __attribute__((unused)) const Matrix<Real> & sigma, const Vector<Real> & epsilon_princ, Real & dam) { Real Fs = epsilon_equ - K0; if (Fs > 0.) { Real dam_t; Real dam_c; dam_t = 1 - K0 * (1 - At) / epsilon_equ - At * (exp(-Bt * (epsilon_equ - K0))); dam_c = 1 - K0 * (1 - Ac) / epsilon_equ - Ac * (exp(-Bc * (epsilon_equ - K0))); Real Cdiag; Cdiag = this->E * (1 - this->nu) / ((1 + this->nu) * (1 - 2 * this->nu)); Vector<Real> sigma_princ(3); sigma_princ(0) = Cdiag * epsilon_princ(0) + this->lambda * (epsilon_princ(1) + epsilon_princ(2)); sigma_princ(1) = Cdiag * epsilon_princ(1) + this->lambda * (epsilon_princ(0) + epsilon_princ(2)); sigma_princ(2) = Cdiag * epsilon_princ(2) + this->lambda * (epsilon_princ(1) + epsilon_princ(0)); Vector<Real> sigma_p(3); for (UInt i = 0; i < 3; i++) sigma_p(i) = std::max(Real(0.), sigma_princ(i)); sigma_p *= 1. - dam; Real trace_p = this->nu / this->E * (sigma_p(0) + sigma_p(1) + sigma_p(2)); Real alpha_t = 0; for (UInt i = 0; i < 3; ++i) { Real epsilon_t = (1 + this->nu) / this->E * sigma_p(i) - trace_p; Real epsilon_p = std::max(Real(0.), epsilon_princ(i)); alpha_t += epsilon_t * epsilon_p; } alpha_t /= epsilon_equ * epsilon_equ; alpha_t = std::min(alpha_t, Real(1.)); Real alpha_c = 1. - alpha_t; alpha_t = std::pow(alpha_t, beta); alpha_c = std::pow(alpha_c, beta); Real damtemp; damtemp = alpha_t * dam_t + alpha_c * dam_c; dam = std::max(damtemp, dam); dam = std::min(dam, Real(1.)); } } /* -------------------------------------------------------------------------- */ // template<UInt spatial_dimension> // inline void // MaterialMazars<spatial_dimension>::computeTangentModuliOnQuad(Matrix<Real> & // tangent) { // MaterialElastic<spatial_dimension>::computeTangentModuliOnQuad(tangent); // tangent *= (1-dam); // } diff --git a/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc b/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc index a0df818db..950334fd3 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc @@ -1,124 +1,123 @@ /** * @file material_mazars_non_local.cc * * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Mon Sep 11 2017 * * @brief Specialization of the material class for the non-local mazars * material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_mazars_non_local.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialMazarsNonLocal<spatial_dimension>::MaterialMazarsNonLocal( SolidMechanicsModel & model, const ID & id) : MaterialNonLocalParent(model, id), Ehat("epsilon_equ", *this), non_local_variable("mazars_non_local", *this) { AKANTU_DEBUG_IN(); this->is_non_local = true; this->Ehat.initialize(1); this->non_local_variable.initialize(1); this->registerParam("average_on_damage", this->damage_in_compute_stress, false, _pat_parsable | _pat_modifiable, "Is D the non local variable"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::registerNonLocalVariables() { ID local; if (this->damage_in_compute_stress) local = this->damage.getName(); else local = this->Ehat.getName(); this->model.getNonLocalManager().registerNonLocalVariable( local, non_local_variable.getName(), 1); this->model.getNonLocalManager() .getNeighborhood(this->name) .registerNonLocalVariable(non_local_variable.getName()); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::computeStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real * damage = this->damage(el_type, ghost_type).storage(); Real * epsilon_equ = this->Ehat(el_type, ghost_type).storage(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); MaterialMazars<spatial_dimension>::computeStressOnQuad(grad_u, sigma, *damage, *epsilon_equ); ++damage; ++epsilon_equ; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::computeNonLocalStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & non_loc_var = non_local_variable(el_type, ghost_type); Real * damage; Real * epsilon_equ; if (this->damage_in_compute_stress) { damage = non_loc_var.storage(); epsilon_equ = this->Ehat(el_type, ghost_type).storage(); } else { damage = this->damage(el_type, ghost_type).storage(); epsilon_equ = non_loc_var.storage(); } MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); this->computeDamageAndStressOnQuad(grad_u, sigma, *damage, *epsilon_equ); ++damage; ++epsilon_equ; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } INSTANTIATE_MATERIAL(mazars_non_local, MaterialMazarsNonLocal); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.hh b/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.hh index e7f28b042..1b5f0f810 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.hh @@ -1,92 +1,91 @@ /** * @file material_mazars_non_local.hh * * @author Marion Estelle Chambart <marion.chambart@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 08 2015 + * @date last modification: Mon Sep 11 2017 * * @brief Mazars non-local description * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_damage_non_local.hh" #include "material_mazars.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_MAZARS_NON_LOCAL_HH__ #define __AKANTU_MATERIAL_MAZARS_NON_LOCAL_HH__ namespace akantu { /** * Material Mazars Non local * * parameters in the material files : */ template <UInt spatial_dimension> class MaterialMazarsNonLocal : public MaterialDamageNonLocal<spatial_dimension, MaterialMazars<spatial_dimension>> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using MaterialNonLocalParent = MaterialDamageNonLocal<spatial_dimension, MaterialMazars<spatial_dimension>>; MaterialMazarsNonLocal(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; void computeNonLocalStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; void registerNonLocalVariables() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// the ehat per quadrature points to perform the averaging InternalField<Real> Ehat; InternalField<Real> non_local_variable; }; } // namespace akantu #endif /* __AKANTU_MATERIAL_MAZARS_NON_LOCAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic.cc b/src/model/solid_mechanics/materials/material_elastic.cc index 894d86e3c..f605cba65 100644 --- a/src/model/solid_mechanics/materials/material_elastic.cc +++ b/src/model/solid_mechanics/materials/material_elastic.cc @@ -1,264 +1,263 @@ /** * @file material_elastic.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Mon Jan 29 2018 * * @brief Specialization of the material class for the elastic material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim> MaterialElastic<dim>::MaterialElastic(SolidMechanicsModel & model, const ID & id) : Parent(model, id), was_stiffness_assembled(false) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> MaterialElastic<dim>::MaterialElastic(SolidMechanicsModel & model, __attribute__((unused)) UInt a_dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Parent(model, dim, mesh, fe_engine, id), was_stiffness_assembled(false) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElastic<dim>::initialize() { this->registerParam("lambda", lambda, _pat_readable, "First Lamé coefficient"); this->registerParam("mu", mu, _pat_readable, "Second Lamé coefficient"); this->registerParam("kapa", kpa, _pat_readable, "Bulk coefficient"); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElastic<dim>::initMaterial() { AKANTU_DEBUG_IN(); Parent::initMaterial(); if (dim == 1) this->nu = 0.; this->updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElastic<dim>::updateInternalParameters() { MaterialThermal<dim>::updateInternalParameters(); this->lambda = this->nu * this->E / ((1 + this->nu) * (1 - 2 * this->nu)); this->mu = this->E / (2 * (1 + this->nu)); this->kpa = this->lambda + 2. / 3. * this->mu; this->was_stiffness_assembled = false; } /* -------------------------------------------------------------------------- */ template <> void MaterialElastic<2>::updateInternalParameters() { MaterialThermal<2>::updateInternalParameters(); this->lambda = this->nu * this->E / ((1 + this->nu) * (1 - 2 * this->nu)); this->mu = this->E / (2 * (1 + this->nu)); if (this->plane_stress) this->lambda = this->nu * this->E / ((1 + this->nu) * (1 - this->nu)); this->kpa = this->lambda + 2. / 3. * this->mu; this->was_stiffness_assembled = false; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialElastic<spatial_dimension>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Parent::computeStress(el_type, ghost_type); Array<Real>::const_scalar_iterator sigma_th_it = this->sigma_th(el_type, ghost_type).begin(); if (!this->finite_deformation) { MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); const Real & sigma_th = *sigma_th_it; this->computeStressOnQuad(grad_u, sigma, sigma_th); ++sigma_th_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } else { /// finite gradus Matrix<Real> E(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); /// compute E this->template gradUToGreenStrain<spatial_dimension>(grad_u, E); const Real & sigma_th = *sigma_th_it; /// compute second Piola-Kirchhoff stress tensor this->computeStressOnQuad(E, sigma, sigma_th); ++sigma_th_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialElastic<spatial_dimension>::computeTangentModuli( const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type) { AKANTU_DEBUG_IN(); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); this->computeTangentModuliOnQuad(tangent); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; this->was_stiffness_assembled = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialElastic<spatial_dimension>::getPushWaveSpeed( const Element &) const { return sqrt((lambda + 2 * mu) / this->rho); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialElastic<spatial_dimension>::getShearWaveSpeed( const Element &) const { return sqrt(mu / this->rho); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialElastic<spatial_dimension>::computePotentialEnergy( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialThermal<spatial_dimension>::computePotentialEnergy(el_type, ghost_type); if (ghost_type != _not_ghost) return; auto epot = this->potential_energy(el_type, ghost_type).begin(); if (!this->finite_deformation) { MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); this->computePotentialEnergyOnQuad(grad_u, sigma, *epot); ++epot; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } else { Matrix<Real> E(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); this->template gradUToGreenStrain<spatial_dimension>(grad_u, E); this->computePotentialEnergyOnQuad(E, sigma, *epot); ++epot; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialElastic<spatial_dimension>::computePotentialEnergyByElement( ElementType type, UInt index, Vector<Real> & epot_on_quad_points) { auto gradu_it = this->gradu(type).begin(spatial_dimension, spatial_dimension); auto gradu_end = this->gradu(type).begin(spatial_dimension, spatial_dimension); auto stress_it = this->stress(type).begin(spatial_dimension, spatial_dimension); if (this->finite_deformation) stress_it = this->piola_kirchhoff_2(type).begin(spatial_dimension, spatial_dimension); UInt nb_quadrature_points = this->fem.getNbIntegrationPoints(type); gradu_it += index * nb_quadrature_points; gradu_end += (index + 1) * nb_quadrature_points; stress_it += index * nb_quadrature_points; Real * epot_quad = epot_on_quad_points.storage(); Matrix<Real> grad_u(spatial_dimension, spatial_dimension); for (; gradu_it != gradu_end; ++gradu_it, ++stress_it, ++epot_quad) { if (this->finite_deformation) this->template gradUToGreenStrain<spatial_dimension>(*gradu_it, grad_u); else grad_u.copy(*gradu_it); this->computePotentialEnergyOnQuad(grad_u, *stress_it, *epot_quad); } } /* -------------------------------------------------------------------------- */ template <> Real MaterialElastic<1>::getPushWaveSpeed(const Element & /*element*/) const { return std::sqrt(this->E / this->rho); } template <> Real MaterialElastic<1>::getShearWaveSpeed(const Element & /*element*/) const { AKANTU_EXCEPTION("There is no shear wave speed in 1D"); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(elastic, MaterialElastic); } // akantu diff --git a/src/model/solid_mechanics/materials/material_elastic.hh b/src/model/solid_mechanics/materials/material_elastic.hh index 805a05107..e442831a7 100644 --- a/src/model/solid_mechanics/materials/material_elastic.hh +++ b/src/model/solid_mechanics/materials/material_elastic.hh @@ -1,157 +1,156 @@ /** * @file material_elastic.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Nov 15 2015 + * @date last modification: Fri Nov 17 2017 * * @brief Material isotropic elastic * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_thermal.hh" #include "plane_stress_toolbox.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_ELASTIC_HH__ #define __AKANTU_MATERIAL_ELASTIC_HH__ namespace akantu { /** * Material elastic isotropic * * parameters in the material files : * - E : Young's modulus (default: 0) * - nu : Poisson's ratio (default: 1/2) * - Plane_Stress : if 0: plane strain, else: plane stress (default: 0) */ template <UInt spatial_dimension> class MaterialElastic : public PlaneStressToolbox<spatial_dimension, MaterialThermal<spatial_dimension>> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ private: using Parent = PlaneStressToolbox<spatial_dimension, MaterialThermal<spatial_dimension>>; public: MaterialElastic(SolidMechanicsModel & model, const ID & id = ""); MaterialElastic(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); ~MaterialElastic() override = default; protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the tangent stiffness matrix for an element type void computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost) override; /// compute the elastic potential energy void computePotentialEnergy(ElementType el_type, GhostType ghost_type = _not_ghost) override; void computePotentialEnergyByElement(ElementType type, UInt index, Vector<Real> & epot_on_quad_points) override; /// compute the p-wave speed in the material Real getPushWaveSpeed(const Element & element) const override; /// compute the s-wave speed in the material Real getShearWaveSpeed(const Element & element) const override; protected: /// constitutive law for a given quadrature point inline void computeStressOnQuad(const Matrix<Real> & grad_u, Matrix<Real> & sigma, const Real sigma_th = 0) const; /// compute the tangent stiffness matrix for an element inline void computeTangentModuliOnQuad(Matrix<Real> & tangent) const; /// recompute the lame coefficient if E or nu changes void updateInternalParameters() override; static inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot); bool hasStiffnessMatrixChanged() override { return (!was_stiffness_assembled); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get first Lame constant AKANTU_GET_MACRO(Lambda, lambda, Real); /// get second Lame constant AKANTU_GET_MACRO(Mu, mu, Real); /// get bulk modulus AKANTU_GET_MACRO(Kappa, kpa, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// First Lamé coefficient Real lambda; /// Second Lamé coefficient (shear modulus) Real mu; /// Bulk modulus Real kpa; /// defines if the stiffness was computed bool was_stiffness_assembled; }; } // akantu #include "material_elastic_inline_impl.cc" #endif /* __AKANTU_MATERIAL_ELASTIC_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_inline_impl.cc b/src/model/solid_mechanics/materials/material_elastic_inline_impl.cc index 6c7160500..606e7bb73 100644 --- a/src/model/solid_mechanics/materials/material_elastic_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_elastic_inline_impl.cc @@ -1,121 +1,120 @@ /** * @file material_elastic_inline_impl.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 04 2010 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Fri Dec 16 2016 * * @brief Implementation of the inline functions of the material elastic * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_ELASTIC_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_ELASTIC_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialElastic<spatial_dimension>::computeStressOnQuad( const Matrix<Real> & grad_u, Matrix<Real> & sigma, const Real sigma_th) const { Real trace = grad_u.trace(); // trace = (\nabla u)_{kk} // \sigma_{ij} = \lambda * (\nabla u)_{kk} * \delta_{ij} + \mu * (\nabla // u_{ij} + \nabla u_{ji}) for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { sigma(i, j) = (i == j) * lambda * trace + mu * (grad_u(i, j) + grad_u(j, i)) + (i == j) * sigma_th; } } } /* -------------------------------------------------------------------------- */ template <> inline void MaterialElastic<1>::computeStressOnQuad(const Matrix<Real> & grad_u, Matrix<Real> & sigma, Real sigma_th) const { sigma(0, 0) = this->E * grad_u(0, 0) + sigma_th; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> inline void MaterialElastic<spatial_dimension>::computeTangentModuliOnQuad( Matrix<Real> & tangent) const { UInt n = tangent.cols(); // Real Ep = E/((1+nu)*(1-2*nu)); Real Miiii = lambda + 2 * mu; Real Miijj = lambda; Real Mijij = mu; if (spatial_dimension == 1) tangent(0, 0) = this->E; else tangent(0, 0) = Miiii; // test of dimension should by optimized out by the compiler due to the // template if (spatial_dimension >= 2) { tangent(1, 1) = Miiii; tangent(0, 1) = Miijj; tangent(1, 0) = Miijj; tangent(n - 1, n - 1) = Mijij; } if (spatial_dimension == 3) { tangent(2, 2) = Miiii; tangent(0, 2) = Miijj; tangent(1, 2) = Miijj; tangent(2, 0) = Miijj; tangent(2, 1) = Miijj; tangent(3, 3) = Mijij; tangent(4, 4) = Mijij; } } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialElastic<dim>::computePotentialEnergyOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot) { epot = .5 * sigma.doubleDot(grad_u); } /* -------------------------------------------------------------------------- */ template <> inline void MaterialElastic<1>::computeTangentModuliOnQuad(Matrix<Real> & tangent) const { tangent(0, 0) = E; } } // akantu #endif /* __AKANTU_MATERIAL_ELASTIC_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc index 84c1608fa..0b8a34b78 100644 --- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc +++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc @@ -1,263 +1,265 @@ /** * @file material_elastic_linear_anisotropic.cc * + * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Till Junge <till.junge@epfl.ch> + * @author Enrico Milanese <enrico.milanese@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 25 2013 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Anisotropic elastic material * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "material_elastic_linear_anisotropic.hh" #include "solid_mechanics_model.hh" #include <algorithm> #include <sstream> namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim> MaterialElasticLinearAnisotropic<dim>::MaterialElasticLinearAnisotropic( SolidMechanicsModel & model, const ID & id, bool symmetric) : Material(model, id), rot_mat(dim, dim), Cprime(dim * dim, dim * dim), C(voigt_h::size, voigt_h::size), eigC(voigt_h::size), symmetric(symmetric), alpha(0), was_stiffness_assembled(false) { AKANTU_DEBUG_IN(); this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim)); (*this->dir_vecs.back())[0] = 1.; this->registerParam("n1", *(this->dir_vecs.back()), _pat_parsmod, "Direction of main material axis"); if (dim > 1) { this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim)); (*this->dir_vecs.back())[1] = 1.; this->registerParam("n2", *(this->dir_vecs.back()), _pat_parsmod, "Direction of secondary material axis"); } if (dim > 2) { this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim)); (*this->dir_vecs.back())[2] = 1.; this->registerParam("n3", *(this->dir_vecs.back()), _pat_parsmod, "Direction of tertiary material axis"); } for (UInt i = 0; i < voigt_h::size; ++i) { UInt start = 0; if (this->symmetric) { start = i; } for (UInt j = start; j < voigt_h::size; ++j) { std::stringstream param("C"); param << "C" << i + 1 << j + 1; this->registerParam(param.str(), this->Cprime(i, j), Real(0.), _pat_parsmod, "Coefficient " + param.str()); } } this->registerParam("alpha", this->alpha, _pat_parsmod, "Proportion of viscous stress"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::updateInternalParameters() { Material::updateInternalParameters(); if (this->symmetric) { for (UInt i = 0; i < voigt_h::size; ++i) { for (UInt j = i + 1; j < voigt_h::size; ++j) { this->Cprime(j, i) = this->Cprime(i, j); } } } this->rotateCprime(); this->C.eig(this->eigC); this->was_stiffness_assembled = false; } /* -------------------------------------------------------------------------- */ template <UInt Dim> void MaterialElasticLinearAnisotropic<Dim>::rotateCprime() { // start by filling the empty parts fo Cprime UInt diff = Dim * Dim - voigt_h::size; for (UInt i = voigt_h::size; i < Dim * Dim; ++i) { for (UInt j = 0; j < Dim * Dim; ++j) { this->Cprime(i, j) = this->Cprime(i - diff, j); } } for (UInt i = 0; i < Dim * Dim; ++i) { for (UInt j = voigt_h::size; j < Dim * Dim; ++j) { this->Cprime(i, j) = this->Cprime(i, j - diff); } } // construction of rotator tensor // normalise rotation matrix for (UInt j = 0; j < Dim; ++j) { Vector<Real> rot_vec = this->rot_mat(j); rot_vec = *this->dir_vecs[j]; rot_vec.normalize(); } // make sure the vectors form a right-handed base Vector<Real> test_axis(3); Vector<Real> v1(3), v2(3), v3(3); if (Dim == 2) { for (UInt i = 0; i < Dim; ++i) { v1[i] = this->rot_mat(0, i); v2[i] = this->rot_mat(1, i); v3[i] = 0.; } v3[2] = 1.; v1[2] = 0.; v2[2] = 0.; } else if (Dim == 3) { v1 = this->rot_mat(0); v2 = this->rot_mat(1); v3 = this->rot_mat(2); } test_axis.crossProduct(v1, v2); test_axis -= v3; if (test_axis.norm() > 8 * std::numeric_limits<Real>::epsilon()) { AKANTU_ERROR("The axis vectors do not form a right-handed coordinate " << "system. I. e., ||n1 x n2 - n3|| should be zero, but " << "it is " << test_axis.norm() << "."); } // create the rotator and the reverse rotator Matrix<Real> rotator(Dim * Dim, Dim * Dim); Matrix<Real> revrotor(Dim * Dim, Dim * Dim); for (UInt i = 0; i < Dim; ++i) { for (UInt j = 0; j < Dim; ++j) { for (UInt k = 0; k < Dim; ++k) { for (UInt l = 0; l < Dim; ++l) { UInt I = voigt_h::mat[i][j]; UInt J = voigt_h::mat[k][l]; rotator(I, J) = this->rot_mat(k, i) * this->rot_mat(l, j); revrotor(I, J) = this->rot_mat(i, k) * this->rot_mat(j, l); } } } } // create the full rotated matrix Matrix<Real> Cfull(Dim * Dim, Dim * Dim); Cfull = rotator * Cprime * revrotor; for (UInt i = 0; i < voigt_h::size; ++i) { for (UInt j = 0; j < voigt_h::size; ++j) { this->C(i, j) = Cfull(i, j); } } } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::computeStress( ElementType el_type, GhostType ghost_type) { // Wikipedia convention: // 2*eps_ij (i!=j) = voigt_eps_I // http://en.wikipedia.org/wiki/Voigt_notation AKANTU_DEBUG_IN(); Matrix<Real> strain(dim, dim); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); this->computeStressOnQuad(strain, sigma); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::computeTangentModuli( const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type) { AKANTU_DEBUG_IN(); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); this->computeTangentModuliOnQuad(tangent); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; this->was_stiffness_assembled = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::computePotentialEnergy( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Material::computePotentialEnergy(el_type, ghost_type); AKANTU_DEBUG_ASSERT(!this->finite_deformation, "finite deformation not possible in material anisotropic " "(TO BE IMPLEMENTED)"); if (ghost_type != _not_ghost) return; Array<Real>::scalar_iterator epot = this->potential_energy(el_type, ghost_type).begin(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computePotentialEnergyOnQuad(grad_u, sigma, *epot); ++epot; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> Real MaterialElasticLinearAnisotropic<dim>::getCelerity( __attribute__((unused)) const Element & element) const { return std::sqrt(this->eigC(0) / rho); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(elastic_anisotropic, MaterialElasticLinearAnisotropic); } // akantu diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh index 2cfa119bb..363378550 100644 --- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh +++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh @@ -1,139 +1,140 @@ /** * @file material_elastic_linear_anisotropic.hh * * @author Till Junge <till.junge@epfl.ch> + * @author Enrico Milanese <enrico.milanese@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Fri Feb 16 2018 * * @brief Orthotropic elastic material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "material_elastic.hh" /* -------------------------------------------------------------------------- */ #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__ #define __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__ namespace akantu { /** * General linear anisotropic elastic material * The only constraint on the elastic tensor is that it can be represented * as a symmetric 6x6 matrix (3D) or 3x3 (2D). * * parameters in the material files : * - rho : density (default: 0) * - C_ij : entry on the stiffness */ template <UInt Dim> class MaterialElasticLinearAnisotropic : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialElasticLinearAnisotropic(SolidMechanicsModel & model, const ID & id = "", bool symmetric = true); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the tangent stiffness matrix for an element type void computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost) override; /// compute the elastic potential energy void computePotentialEnergy(ElementType el_type, GhostType ghost_type = _not_ghost) override; void updateInternalParameters() override; bool hasStiffnessMatrixChanged() override { return (!was_stiffness_assembled); } protected: // compute C from Cprime void rotateCprime(); /// constitutive law for a given quadrature point inline void computeStressOnQuad(const Matrix<Real> & grad_u, Matrix<Real> & sigma) const; /// tangent matrix for a given quadrature point inline void computeTangentModuliOnQuad(Matrix<Real> & tangent) const; inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// compute max wave celerity Real getCelerity(const Element & element) const override; AKANTU_GET_MACRO(VoigtStiffness, C, Matrix<Real>); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: using voigt_h = VoigtHelper<Dim>; /// direction matrix and vectors std::vector<std::unique_ptr<Vector<Real>>> dir_vecs; Matrix<Real> rot_mat; /// Elastic stiffness tensor in material frame and full vectorised notation Matrix<Real> Cprime; /// Elastic stiffness tensor in voigt notation Matrix<Real> C; /// eigenvalues of stiffness tensor Vector<Real> eigC; bool symmetric; /// viscous proportion Real alpha; /// defines if the stiffness was computed bool was_stiffness_assembled; }; } // akantu #include "material_elastic_linear_anisotropic_inline_impl.cc" #endif /* __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc index 1d608fe60..716978f67 100644 --- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc @@ -1,93 +1,92 @@ /** * @file material_elastic_linear_anisotropic_inline_impl.cc * * @author Enrico Milanese <enrico.milanese@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Mon Feb 12 2018 - * @date last modification: Mon Feb 12 2018 + * @date creation: Fri Feb 16 2018 + * @date last modification: Fri Feb 16 2018 * - * @brief Implementation of the inline functions of the material elastic linear + * @brief Implementation of the inline functions of the material elastic linear * anisotropic * * @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) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_elastic_linear_anisotropic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialElasticLinearAnisotropic<dim>::computeStressOnQuad( const Matrix<Real> & grad_u, Matrix<Real> & sigma) const { // Wikipedia convention: // 2*eps_ij (i!=j) = voigt_eps_I // http://en.wikipedia.org/wiki/Voigt_notation Vector<Real> voigt_strain(voigt_h::size); Vector<Real> voigt_stress(voigt_h::size); for (UInt I = 0; I < voigt_h::size; ++I) { Real voigt_factor = voigt_h::factors[I]; UInt i = voigt_h::vec[I][0]; UInt j = voigt_h::vec[I][1]; voigt_strain(I) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.; } voigt_stress = this->C * voigt_strain; for (UInt I = 0; I < voigt_h::size; ++I) { UInt i = voigt_h::vec[I][0]; UInt j = voigt_h::vec[I][1]; sigma(i, j) = sigma(j, i) = voigt_stress(I); } } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialElasticLinearAnisotropic<dim>::computeTangentModuliOnQuad( Matrix<Real> & tangent) const { tangent.copy(this->C); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialElasticLinearAnisotropic<dim>::computePotentialEnergyOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot) { AKANTU_DEBUG_ASSERT(this->symmetric, "The elastic constants matrix is not symmetric," "energy is not path independent."); epot = .5 * sigma.doubleDot(grad_u); } } // akantu #endif /* __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc b/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc index 320f2bb44..d701bf394 100644 --- a/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc +++ b/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc @@ -1,168 +1,168 @@ /** * @file material_elastic_orthotropic.cc * * @author Till Junge <till.junge@epfl.ch> + * @author Enrico Milanese <enrico.milanese@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Orthotropic elastic material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "material_elastic_orthotropic.hh" #include "solid_mechanics_model.hh" #include <algorithm> namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt Dim> MaterialElasticOrthotropic<Dim>::MaterialElasticOrthotropic( SolidMechanicsModel & model, const ID & id) : MaterialElasticLinearAnisotropic<Dim>(model, id) { AKANTU_DEBUG_IN(); this->registerParam("E1", E1, Real(0.), _pat_parsmod, "Young's modulus (n1)"); this->registerParam("E2", E2, Real(0.), _pat_parsmod, "Young's modulus (n2)"); this->registerParam("nu12", nu12, Real(0.), _pat_parsmod, "Poisson's ratio (12)"); this->registerParam("G12", G12, Real(0.), _pat_parsmod, "Shear modulus (12)"); if (Dim > 2) { this->registerParam("E3", E3, Real(0.), _pat_parsmod, "Young's modulus (n3)"); this->registerParam("nu13", nu13, Real(0.), _pat_parsmod, "Poisson's ratio (13)"); this->registerParam("nu23", nu23, Real(0.), _pat_parsmod, "Poisson's ratio (23)"); this->registerParam("G13", G13, Real(0.), _pat_parsmod, "Shear modulus (13)"); this->registerParam("G23", G23, Real(0.), _pat_parsmod, "Shear modulus (23)"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt Dim> void MaterialElasticOrthotropic<Dim>::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt Dim> void MaterialElasticOrthotropic<Dim>::updateInternalParameters() { /* 1) construction of temporary material frame stiffness tensor------------ */ // http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real nu31 = nu13 * E3 / E1; Real nu32 = nu23 * E3 / E2; // Full (i.e. dim^2 by dim^2) stiffness tensor in material frame if (Dim == 1) { AKANTU_ERROR("Dimensions 1 not implemented: makes no sense to have " "orthotropy for 1D"); } Real Gamma; if (Dim == 3) Gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - 2 * nu21 * nu32 * nu13); if (Dim == 2) Gamma = 1 / (1 - nu12 * nu21); // Lamé's first parameters this->Cprime(0, 0) = E1 * (1 - nu23 * nu32) * Gamma; this->Cprime(1, 1) = E2 * (1 - nu13 * nu31) * Gamma; if (Dim == 3) this->Cprime(2, 2) = E3 * (1 - nu12 * nu21) * Gamma; // normalised poisson's ratio's this->Cprime(1, 0) = this->Cprime(0, 1) = E1 * (nu21 + nu31 * nu23) * Gamma; if (Dim == 3) { this->Cprime(2, 0) = this->Cprime(0, 2) = E1 * (nu31 + nu21 * nu32) * Gamma; this->Cprime(2, 1) = this->Cprime(1, 2) = E2 * (nu32 + nu12 * nu31) * Gamma; } // Lamé's second parameters (shear moduli) if (Dim == 3) { this->Cprime(3, 3) = G23; this->Cprime(4, 4) = G13; this->Cprime(5, 5) = G12; } else this->Cprime(2, 2) = G12; /* 1) rotation of C into the global frame */ this->rotateCprime(); this->C.eig(this->eigC); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialElasticOrthotropic<spatial_dimension>:: computePotentialEnergyByElement(ElementType type, UInt index, Vector<Real> & epot_on_quad_points) { AKANTU_DEBUG_ASSERT(!this->finite_deformation, "finite deformation not possible in material orthotropic " "(TO BE IMPLEMENTED)"); Array<Real>::matrix_iterator gradu_it = this->gradu(type).begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator gradu_end = this->gradu(type).begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator stress_it = this->stress(type).begin(spatial_dimension, spatial_dimension); UInt nb_quadrature_points = this->fem.getNbIntegrationPoints(type); gradu_it += index * nb_quadrature_points; gradu_end += (index + 1) * nb_quadrature_points; stress_it += index * nb_quadrature_points; Real * epot_quad = epot_on_quad_points.storage(); Matrix<Real> grad_u(spatial_dimension, spatial_dimension); for (; gradu_it != gradu_end; ++gradu_it, ++stress_it, ++epot_quad) { grad_u.copy(*gradu_it); this->computePotentialEnergyOnQuad(grad_u, *stress_it, *epot_quad); } } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(elastic_orthotropic, MaterialElasticOrthotropic); } // akantu diff --git a/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh b/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh index 60110342c..0cea87042 100644 --- a/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh +++ b/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh @@ -1,136 +1,136 @@ /** * @file material_elastic_orthotropic.hh * * @author Till Junge <till.junge@epfl.ch> + * @author Enrico Milanese <enrico.milanese@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Fri Feb 16 2018 * * @brief Orthotropic elastic material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_elastic_linear_anisotropic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__ #define __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__ namespace akantu { /** * Orthotropic elastic material * * parameters in the material files : * - n1 : direction of x-axis in material base, normalisation not necessary * (default: {1, 0, 0}) * - n2 : direction of y-axis in material base, normalisation not necessary * (default: {0, 1, 0}) * - n3 : direction of z-axis in material base, normalisation not necessary * (default: {0, 0, 1}) * - rho : density (default: 0) * - E1 : Young's modulus along n1 (default: 0) * - E2 : Young's modulus along n2 (default: 0) * - E3 : Young's modulus along n3 (default: 0) * - nu12 : Poisson's ratio along 12 (default: 0) * - nu13 : Poisson's ratio along 13 (default: 0) * - nu23 : Poisson's ratio along 23 (default: 0) * - G12 : Shear modulus along 12 (default: 0) * - G13 : Shear modulus along 13 (default: 0) * - G23 : Shear modulus along 23 (default: 0) */ template <UInt Dim> class MaterialElasticOrthotropic : public MaterialElasticLinearAnisotropic<Dim> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialElasticOrthotropic(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; void updateInternalParameters() override; void computePotentialEnergyByElement(ElementType type, UInt index, Vector<Real> & epot_on_quad_points) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(E1, E1, Real); AKANTU_GET_MACRO(E2, E2, Real); AKANTU_GET_MACRO(E3, E3, Real); AKANTU_GET_MACRO(Nu12, nu12, Real); AKANTU_GET_MACRO(Nu13, nu13, Real); AKANTU_GET_MACRO(Nu23, nu23, Real); AKANTU_GET_MACRO(G12, G12, Real); AKANTU_GET_MACRO(G13, G13, Real); AKANTU_GET_MACRO(G23, G23, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the n1 young modulus Real E1; /// the n2 young modulus Real E2; /// the n3 young modulus Real E3; /// 12 Poisson coefficient Real nu12; /// 13 Poisson coefficient Real nu13; /// 23 Poisson coefficient Real nu23; /// 12 shear modulus Real G12; /// 13 shear modulus Real G13; /// 23 shear modulus Real G23; }; } // akantu #endif /* __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh b/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh index 29362ed2c..fa1a1f523 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh @@ -1,41 +1,41 @@ /** * @file material_embedded_includes.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jan 04 2013 - * @date last modification: Fri May 29 2015 + * @date last modification: Fri Feb 09 2018 * * @brief List of includes for embedded elements * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_CMAKE_LIST_MATERIALS #include "material_reinforcement.hh" #endif #define AKANTU_MATERIAL_REINFORCEMENT_LAW_TMPL_LIST \ ((elastic, (MaterialElastic<1>)))( \ (plastic, (MaterialLinearIsotropicHardening<1>))) #define AKANTU_EMBEDDED_MATERIAL_LIST \ ((2, (reinforcement, MaterialReinforcement))) diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh index 172508a2e..36a04ab7f 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh @@ -1,209 +1,209 @@ /** * @file material_reinforcement.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Mar 13 2015 - * @date last modification: Tue Nov 24 2015 + * @date last modification: Fri Feb 09 2018 * * @brief Reinforcement material * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_REINFORCEMENT_HH__ #define __AKANTU_MATERIAL_REINFORCEMENT_HH__ #include "aka_common.hh" #include "embedded_interface_model.hh" #include "material.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /** * @brief Material used to represent embedded reinforcements * * This class is used for computing the reinforcement stiffness matrix * along with the reinforcement residual. Room is made for constitutive law, * but actual use of contitutive laws is made in MaterialReinforcementTemplate. * * Be careful with the dimensions in this class : * - this->spatial_dimension is always 1 * - the template parameter dim is the dimension of the problem */ template <class Mat, UInt dim> class MaterialReinforcement : public Mat { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// Constructor MaterialReinforcement(EmbeddedInterfaceModel & model, const ID & id = ""); /// Destructor ~MaterialReinforcement() override; protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Init the material void initMaterial() override; /// Init the filters for background elements void initFilters(); /// Init the background shape derivatives void initBackgroundShapeDerivatives(); /// Init the cosine matrices void initDirectingCosines(); /// Assemble stiffness matrix void assembleStiffnessMatrix(GhostType ghost_type) override; /// Compute all the stresses ! void computeAllStresses(GhostType ghost_type) override; /// Compute energy Real getEnergy(const std::string & id) override; /// Assemble the residual of one type of element (typically _segment_2) void assembleInternalForces(GhostType ghost_type) override; /* ------------------------------------------------------------------------ */ /* Protected methods */ /* ------------------------------------------------------------------------ */ protected: /// Allocate the background shape derivatives void allocBackgroundShapeDerivatives(); /// Compute the directing cosines matrix for one element type void computeDirectingCosines(const ElementType & type, GhostType ghost_type); /// Compute the directing cosines matrix on quadrature points. inline void computeDirectingCosinesOnQuad(const Matrix<Real> & nodes, Matrix<Real> & cosines); /// Add the prestress to the computed stress void addPrestress(const ElementType & type, GhostType ghost_type); /// Compute displacement gradient in reinforcement void computeGradU(const ElementType & interface_type, GhostType ghost_type); /// Assemble the stiffness matrix for an element type (typically _segment_2) void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// Assemble the stiffness matrix for background & interface types void assembleStiffnessMatrixInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type); /// Compute the background shape derivatives for a type void computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type); /// Compute the background shape derivatives for a type pair void computeBackgroundShapeDerivatives(const ElementType & interface_type, const ElementType & bg_type, GhostType ghost_type, const Array<UInt> & filter); /// Filter elements crossed by interface of a type void filterInterfaceBackgroundElements(Array<UInt> & foreground, Array<UInt> & background, const ElementType & type, const ElementType & interface_type, GhostType ghost_type); /// Assemble the residual of one type of element (typically _segment_2) void assembleInternalForces(const ElementType & type, GhostType ghost_type); /// Assemble the residual for a pair of elements void assembleInternalForcesInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type); // TODO figure out why voigt size is 4 in 2D inline void stressTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); inline void strainTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); /// Get background filter Array<UInt> & getBackgroundFilter(const ElementType & fg_type, const ElementType & bg_type, GhostType ghost_type) { return (*background_filter(fg_type, ghost_type))(bg_type, ghost_type); } /// Get foreground filter Array<UInt> & getForegroundFilter(const ElementType & fg_type, const ElementType & bg_type, GhostType ghost_type) { return (*foreground_filter(fg_type, ghost_type))(bg_type, ghost_type); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Embedded model EmbeddedInterfaceModel & emodel; /// Gradu of concrete on reinforcement InternalField<Real> gradu_embedded; /// C matrix on quad InternalField<Real> directing_cosines; /// Prestress on quad InternalField<Real> pre_stress; /// Cross-sectional area Real area; template <typename T> using CrossMap = ElementTypeMap<std::unique_ptr<ElementTypeMapArray<T>>>; /// Background mesh shape derivatives CrossMap<Real> shape_derivatives; /// Foreground mesh filter (contains segment ids) CrossMap<UInt> foreground_filter; /// Background element filter (contains bg ids) CrossMap<UInt> background_filter; }; } // akantu #include "material_reinforcement_tmpl.hh" #endif // __AKANTU_MATERIAL_REINFORCEMENT_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh index e8f8c5ef9..dadf9e27e 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh @@ -1,800 +1,801 @@ /** * @file material_reinforcement_tmpl.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * - * @date creation: Thu Feb 1 2018 + * @date creation: Wed Mar 25 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Reinforcement material * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_voigthelper.hh" #include "material_reinforcement.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> MaterialReinforcement<Mat, dim>::MaterialReinforcement( EmbeddedInterfaceModel & model, const ID & id) : Mat(model, 1, model.getInterfaceMesh(), model.getFEEngine("EmbeddedInterfaceFEEngine"), id), emodel(model), gradu_embedded("gradu_embedded", *this, 1, model.getFEEngine("EmbeddedInterfaceFEEngine"), this->element_filter), directing_cosines("directing_cosines", *this, 1, model.getFEEngine("EmbeddedInterfaceFEEngine"), this->element_filter), pre_stress("pre_stress", *this, 1, model.getFEEngine("EmbeddedInterfaceFEEngine"), this->element_filter), area(1.0), shape_derivatives() { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initialize() { AKANTU_DEBUG_IN(); this->registerParam("area", area, _pat_parsable | _pat_modifiable, "Reinforcement cross-sectional area"); this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable, "Uniform pre-stress"); // this->unregisterInternal(this->stress); // Fool the AvgHomogenizingFunctor // stress.initialize(dim * dim); // Reallocate the element filter this->element_filter.initialize(this->emodel.getInterfaceMesh(), _spatial_dimension = 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> MaterialReinforcement<Mat, dim>::~MaterialReinforcement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initMaterial() { Mat::initMaterial(); gradu_embedded.initialize(dim * dim); pre_stress.initialize(1); /// We initialise the stuff that is not going to change during the simulation this->initFilters(); this->allocBackgroundShapeDerivatives(); this->initBackgroundShapeDerivatives(); this->initDirectingCosines(); } /* -------------------------------------------------------------------------- */ /// Initialize the filter for background elements template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initFilters() { for (auto gt : ghost_types) { for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) { std::string shaped_id = "filter"; if (gt == _ghost) shaped_id += ":ghost"; auto & background = background_filter(std::make_unique<ElementTypeMapArray<UInt>>( "bg_" + shaped_id, this->name), type, gt); auto & foreground = foreground_filter( std::make_unique<ElementTypeMapArray<UInt>>(shaped_id, this->name), type, gt); foreground->initialize(emodel.getMesh(), _nb_component = 1, _ghost_type = gt); background->initialize(emodel.getMesh(), _nb_component = 1, _ghost_type = gt); // Computing filters for (auto && bg_type : background->elementTypes(dim, gt)) { filterInterfaceBackgroundElements( (*foreground)(bg_type), (*background)(bg_type), bg_type, type, gt); } } } } /* -------------------------------------------------------------------------- */ /// Construct a filter for a (interface_type, background_type) pair template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::filterInterfaceBackgroundElements( Array<UInt> & foreground, Array<UInt> & background, const ElementType & type, const ElementType & interface_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); foreground.resize(0); background.resize(0); Array<Element> & elements = emodel.getInterfaceAssociatedElements(interface_type, ghost_type); Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); for (auto & elem_id : elem_filter) { Element & elem = elements(elem_id); if (elem.type == type) { background.push_back(elem.element); foreground.push_back(elem_id); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ namespace detail { class BackgroundShapeDInitializer : public ElementTypeMapArrayInitializer { public: BackgroundShapeDInitializer(UInt spatial_dimension, FEEngine & engine, const ElementType & foreground_type, const ElementTypeMapArray<UInt> & filter, const GhostType & ghost_type) : ElementTypeMapArrayInitializer( [](const ElementType & bgtype, const GhostType &) { return ShapeFunctions::getShapeDerivativesSize(bgtype); }, spatial_dimension, ghost_type, _ek_regular) { auto nb_quad = engine.getNbIntegrationPoints(foreground_type); // Counting how many background elements are affected by elements of // interface_type for (auto type : filter.elementTypes(this->spatial_dimension)) { // Inserting size array_size_per_bg_type(filter(type).size() * nb_quad, type, this->ghost_type); } } auto elementTypes() const -> decltype(auto) { return array_size_per_bg_type.elementTypes(); } UInt size(const ElementType & bgtype) const { return array_size_per_bg_type(bgtype, this->ghost_type); } protected: ElementTypeMap<UInt> array_size_per_bg_type; }; } /** * Background shape derivatives need to be stored per background element * types but also per embedded element type, which is why they are stored * in an ElementTypeMap<ElementTypeMapArray<Real> *>. The outer ElementTypeMap * refers to the embedded types, and the inner refers to the background types. */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::allocBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); for (auto gt : ghost_types) { for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) { std::string shaped_id = "embedded_shape_derivatives"; if (gt == _ghost) shaped_id += ":ghost"; auto & shaped_etma = shape_derivatives( std::make_unique<ElementTypeMapArray<Real>>(shaped_id, this->name), type, gt); shaped_etma->initialize( detail::BackgroundShapeDInitializer( emodel.getSpatialDimension(), emodel.getFEEngine("EmbeddedInterfaceFEEngine"), type, *background_filter(type, gt), gt), 0, true); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); for (auto interface_type : this->element_filter.elementTypes(this->spatial_dimension)) { for (auto type : background_filter(interface_type)->elementTypes(dim)) { computeBackgroundShapeDerivatives(interface_type, type, _not_ghost, this->element_filter(interface_type)); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeBackgroundShapeDerivatives( const ElementType & interface_type, const ElementType & bg_type, GhostType ghost_type, const Array<UInt> & filter) { auto & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); auto & engine = emodel.getFEEngine(); auto & interface_mesh = emodel.getInterfaceMesh(); const auto nb_nodes_elem_bg = Mesh::getNbNodesPerElement(bg_type); // const auto nb_strss = VoigtHelper<dim>::size; const auto nb_quads_per_elem = interface_engine.getNbIntegrationPoints(interface_type); Array<Real> quad_pos(0, dim, "interface_quad_pos"); interface_engine.interpolateOnIntegrationPoints(interface_mesh.getNodes(), quad_pos, dim, interface_type, ghost_type, filter); auto & background_shapesd = (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type); auto & background_elements = (*background_filter(interface_type, ghost_type))(bg_type, ghost_type); auto & foreground_elements = (*foreground_filter(interface_type, ghost_type))(bg_type, ghost_type); auto shapesd_begin = background_shapesd.begin(dim, nb_nodes_elem_bg, nb_quads_per_elem); auto quad_begin = quad_pos.begin(dim, nb_quads_per_elem); for (auto && tuple : zip(background_elements, foreground_elements)) { UInt bg = std::get<0>(tuple), fg = std::get<1>(tuple); for (UInt i = 0; i < nb_quads_per_elem; ++i) { Matrix<Real> shapesd = Tensor3<Real>(shapesd_begin[fg])(i); Vector<Real> quads = Matrix<Real>(quad_begin[fg])(i); engine.computeShapeDerivatives(quads, bg, bg_type, shapesd, ghost_type); } } } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initDirectingCosines() { AKANTU_DEBUG_IN(); Mesh & mesh = emodel.getInterfaceMesh(); Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost); const UInt voigt_size = VoigtHelper<dim>::size; directing_cosines.initialize(voigt_size); for (; type_it != type_end; ++type_it) { computeDirectingCosines(*type_it, _not_ghost); // computeDirectingCosines(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix( GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = emodel.getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); for (; type_it != type_end; ++type_it) { assembleStiffnessMatrix(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleInternalForces( GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = emodel.getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); for (; type_it != type_end; ++type_it) { this->assembleInternalForces(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = emodel.getInterfaceMesh().firstType(); Mesh::type_iterator last_type = emodel.getInterfaceMesh().lastType(); for (; it != last_type; ++it) { computeGradU(*it, ghost_type); this->computeStress(*it, ghost_type); addPrestress(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::addPrestress(const ElementType & type, GhostType ghost_type) { auto & stress = this->stress(type, ghost_type); auto & sigma_p = this->pre_stress(type, ghost_type); for (auto && tuple : zip(stress, sigma_p)) { std::get<0>(tuple) += std::get<1>(tuple); } } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleInternalForces( const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = emodel.getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end; ++type_it) { assembleInternalForcesInterface(type, *type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Computes and assemble the residual. Residual in reinforcement is computed as: * * \f[ * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s} * \f] */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleInternalForcesInterface( const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt voigt_size = VoigtHelper<dim>::size; FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbIntegrationPoints(interface_type, ghost_type); UInt nb_element = elem_filter.size(); UInt back_dof = dim * nodes_per_background_e; Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( background_type, ghost_type); Array<Real> integrant(nb_quadrature_points * nb_element, back_dof, "integrant"); auto integrant_it = integrant.begin(back_dof); auto integrant_end = integrant.end(back_dof); Array<Real>::matrix_iterator B_it = shapesd.begin(dim, nodes_per_background_e); auto C_it = directing_cosines(interface_type, ghost_type).begin(voigt_size); auto sigma_it = this->stress(interface_type, ghost_type).begin(); Matrix<Real> Bvoigt(voigt_size, back_dof); for (; integrant_it != integrant_end; ++integrant_it, ++B_it, ++C_it, ++sigma_it) { VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, nodes_per_background_e); Vector<Real> & C = *C_it; Vector<Real> & BtCt_sigma = *integrant_it; BtCt_sigma.mul<true>(Bvoigt, C); BtCt_sigma *= *sigma_it * area; } Array<Real> residual_interface(nb_element, back_dof, "residual_interface"); interface_engine.integrate(integrant, residual_interface, back_dof, interface_type, ghost_type, elem_filter); integrant.resize(0); Array<UInt> background_filter(nb_element, 1, "background_filter"); auto & filter = getBackgroundFilter(interface_type, background_type, ghost_type); emodel.getDOFManager().assembleElementalArrayLocalArray( residual_interface, emodel.getInternalForce(), background_type, ghost_type, -1., filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeDirectingCosines( const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = emodel.getInterfaceMesh(); const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const UInt steel_dof = dim * nb_nodes_per_element; const UInt voigt_size = VoigtHelper<dim>::size; const UInt nb_quad_points = emodel.getFEEngine("EmbeddedInterfaceFEEngine") .getNbIntegrationPoints(type, ghost_type); Array<Real> node_coordinates(this->element_filter(type, ghost_type).size(), steel_dof); this->emodel.getFEEngine().template extractNodalToElementField<Real>( interface_mesh, interface_mesh.getNodes(), node_coordinates, type, ghost_type, this->element_filter(type, ghost_type)); Array<Real>::matrix_iterator directing_cosines_it = directing_cosines(type, ghost_type).begin(1, voigt_size); Array<Real>::matrix_iterator node_coordinates_it = node_coordinates.begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator node_coordinates_end = node_coordinates.end(dim, nb_nodes_per_element); for (; node_coordinates_it != node_coordinates_end; ++node_coordinates_it) { for (UInt i = 0; i < nb_quad_points; i++, ++directing_cosines_it) { Matrix<Real> & nodes = *node_coordinates_it; Matrix<Real> & cosines = *directing_cosines_it; computeDirectingCosinesOnQuad(nodes, cosines); } } // Mauro: the directing_cosines internal is defined on the quadrature points // of each element AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix( const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = emodel.getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end; ++type_it) { assembleStiffnessMatrixInterface(type, *type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001) * \f[ * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}} * \f] */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrixInterface( const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt voigt_size = VoigtHelper<dim>::size; FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); Array<Real> & grad_u = gradu_embedded(interface_type, ghost_type); UInt nb_element = elem_filter.size(); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbIntegrationPoints(interface_type, ghost_type); UInt back_dof = dim * nodes_per_background_e; UInt integrant_size = back_dof; grad_u.resize(nb_quadrature_points * nb_element); Array<Real> tangent_moduli(nb_element * nb_quadrature_points, 1, "interface_tangent_moduli"); this->computeTangentModuli(interface_type, tangent_moduli, ghost_type); Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( background_type, ghost_type); Array<Real> integrant(nb_element * nb_quadrature_points, integrant_size * integrant_size, "B^t*C^t*D*C*B"); /// Temporary matrices for integrant product Matrix<Real> Bvoigt(voigt_size, back_dof); Matrix<Real> DCB(1, back_dof); Matrix<Real> CtDCB(voigt_size, back_dof); Array<Real>::scalar_iterator D_it = tangent_moduli.begin(); Array<Real>::scalar_iterator D_end = tangent_moduli.end(); Array<Real>::matrix_iterator C_it = directing_cosines(interface_type, ghost_type).begin(1, voigt_size); Array<Real>::matrix_iterator B_it = shapesd.begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator integrant_it = integrant.begin(integrant_size, integrant_size); for (; D_it != D_end; ++D_it, ++C_it, ++B_it, ++integrant_it) { Real & D = *D_it; Matrix<Real> & C = *C_it; Matrix<Real> & B = *B_it; Matrix<Real> & BtCtDCB = *integrant_it; VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt, nodes_per_background_e); DCB.mul<false, false>(C, Bvoigt); DCB *= D * area; CtDCB.mul<true, false>(C, DCB); BtCtDCB.mul<true, false>(Bvoigt, CtDCB); } tangent_moduli.resize(0); Array<Real> K_interface(nb_element, integrant_size * integrant_size, "K_interface"); interface_engine.integrate(integrant, K_interface, integrant_size * integrant_size, interface_type, ghost_type, elem_filter); integrant.resize(0); // Mauro: Here K_interface contains the local stiffness matrices, // directing_cosines contains the information about the orientation // of the reinforcements, any rotation of the local stiffness matrix // can be done here auto & filter = getBackgroundFilter(interface_type, background_type, ghost_type); emodel.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", K_interface, background_type, ghost_type, _symmetric, filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> Real MaterialReinforcement<Mat, dim>::getEnergy(const std::string & id) { AKANTU_DEBUG_IN(); if (id == "potential") { Real epot = 0.; this->computePotentialEnergyByElements(); Mesh::type_iterator it = this->element_filter.firstType( this->spatial_dimension), end = this->element_filter.lastType( this->spatial_dimension); for (; it != end; ++it) { FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); epot += interface_engine.integrate( this->potential_energy(*it, _not_ghost), *it, _not_ghost, this->element_filter(*it, _not_ghost)); epot *= area; } return epot; } AKANTU_DEBUG_OUT(); return 0; } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeGradU( const ElementType & interface_type, GhostType ghost_type) { // Looping over background types for (auto && bg_type : background_filter(interface_type, ghost_type)->elementTypes(dim)) { const UInt nodes_per_background_e = Mesh::getNbNodesPerElement(bg_type); const UInt voigt_size = VoigtHelper<dim>::size; auto & bg_shapesd = (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type); auto & filter = getBackgroundFilter(interface_type, bg_type, ghost_type); Array<Real> disp_per_element(0, dim * nodes_per_background_e, "disp_elem"); FEEngine::extractNodalToElementField( emodel.getMesh(), emodel.getDisplacement(), disp_per_element, bg_type, ghost_type, filter); Matrix<Real> concrete_du(dim, dim); Matrix<Real> epsilon(dim, dim); Vector<Real> evoigt(voigt_size); for (auto && tuple : zip(make_view(disp_per_element, dim, nodes_per_background_e), make_view(bg_shapesd, dim, nodes_per_background_e), this->gradu(interface_type, ghost_type), make_view(this->directing_cosines(interface_type, ghost_type), voigt_size))) { auto & u = std::get<0>(tuple); auto & B = std::get<1>(tuple); auto & du = std::get<2>(tuple); auto & C = std::get<3>(tuple); concrete_du.mul<false, true>(u, B); auto epsilon = 0.5 * (concrete_du + concrete_du.transpose()); strainTensorToVoigtVector(epsilon, evoigt); du = C.dot(evoigt); } } } /* -------------------------------------------------------------------------- */ /** * The structure of the directing cosines matrix is : * \f{eqnarray*}{ * C_{1,\cdot} & = & (l^2, m^2, n^2, mn, ln, lm) \\ * C_{i,j} & = & 0 * \f} * * with : * \f[ * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot * \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s} * \f] */ template <class Mat, UInt dim> inline void MaterialReinforcement<Mat, dim>::computeDirectingCosinesOnQuad( const Matrix<Real> & nodes, Matrix<Real> & cosines) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(nodes.cols() == 2, "Higher order reinforcement elements not implemented"); const Vector<Real> a = nodes(0), b = nodes(1); Vector<Real> delta = b - a; Real sq_length = 0.; for (UInt i = 0; i < dim; i++) { sq_length += delta(i) * delta(i); } if (dim == 2) { cosines(0, 0) = delta(0) * delta(0); // l^2 cosines(0, 1) = delta(1) * delta(1); // m^2 cosines(0, 2) = delta(0) * delta(1); // lm } else if (dim == 3) { cosines(0, 0) = delta(0) * delta(0); // l^2 cosines(0, 1) = delta(1) * delta(1); // m^2 cosines(0, 2) = delta(2) * delta(2); // n^2 cosines(0, 3) = delta(1) * delta(2); // mn cosines(0, 4) = delta(0) * delta(2); // ln cosines(0, 5) = delta(0) * delta(1); // lm } cosines /= sq_length; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> inline void MaterialReinforcement<Mat, dim>::stressTensorToVoigtVector( const Matrix<Real> & tensor, Vector<Real> & vector) { AKANTU_DEBUG_IN(); for (UInt i = 0; i < dim; i++) { vector(i) = tensor(i, i); } if (dim == 2) { vector(2) = tensor(0, 1); } else if (dim == 3) { vector(3) = tensor(1, 2); vector(4) = tensor(0, 2); vector(5) = tensor(0, 1); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> inline void MaterialReinforcement<Mat, dim>::strainTensorToVoigtVector( const Matrix<Real> & tensor, Vector<Real> & vector) { AKANTU_DEBUG_IN(); for (UInt i = 0; i < dim; i++) { vector(i) = tensor(i, i); } if (dim == 2) { vector(2) = 2 * tensor(0, 1); } else if (dim == 3) { vector(3) = 2 * tensor(1, 2); vector(4) = 2 * tensor(0, 2); vector(5) = 2 * tensor(0, 1); } AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc b/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc index 1f2e92ac8..bf8906b65 100644 --- a/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc +++ b/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc @@ -1,287 +1,287 @@ /** * @file material_neohookean.cc * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * * @date creation: Mon Apr 08 2013 - * @date last modification: Tue Aug 04 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Specialization of the material class for finite deformation * neo-hookean material * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_neohookean.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialNeohookean<spatial_dimension>::MaterialNeohookean( SolidMechanicsModel & model, const ID & id) : PlaneStressToolbox<spatial_dimension>(model, id) { AKANTU_DEBUG_IN(); this->registerParam("E", E, Real(0.), _pat_parsable | _pat_modifiable, "Young's modulus"); this->registerParam("nu", nu, Real(0.5), _pat_parsable | _pat_modifiable, "Poisson's ratio"); this->registerParam("lambda", lambda, _pat_readable, "First Lamé coefficient"); this->registerParam("mu", mu, _pat_readable, "Second Lamé coefficient"); this->registerParam("kapa", kpa, _pat_readable, "Bulk coefficient"); this->finite_deformation = true; this->initialize_third_axis_deformation = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialNeohookean<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); PlaneStressToolbox<spatial_dimension>::initMaterial(); if (spatial_dimension == 1) nu = 0.; this->updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void MaterialNeohookean<2>::initMaterial() { AKANTU_DEBUG_IN(); PlaneStressToolbox<2>::initMaterial(); this->updateInternalParameters(); if (this->plane_stress) this->third_axis_deformation.setDefaultValue(1.); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialNeohookean<spatial_dimension>::updateInternalParameters() { lambda = nu * E / ((1 + nu) * (1 - 2 * nu)); mu = E / (2 * (1 + nu)); kpa = lambda + 2. / 3. * mu; } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialNeohookean<dim>::computeCauchyStressPlaneStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); PlaneStressToolbox<dim>::computeCauchyStressPlaneStress(el_type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void MaterialNeohookean<2>::computeCauchyStressPlaneStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::matrix_iterator gradu_it = this->gradu(el_type, ghost_type).begin(2, 2); Array<Real>::matrix_iterator gradu_end = this->gradu(el_type, ghost_type).end(2, 2); Array<Real>::matrix_iterator piola_it = this->piola_kirchhoff_2(el_type, ghost_type).begin(2, 2); Array<Real>::matrix_iterator stress_it = this->stress(el_type, ghost_type).begin(2, 2); Array<Real>::const_scalar_iterator c33_it = this->third_axis_deformation(el_type, ghost_type).begin(); Matrix<Real> F_tensor(2, 2); for (; gradu_it != gradu_end; ++gradu_it, ++piola_it, ++stress_it, ++c33_it) { Matrix<Real> & grad_u = *gradu_it; Matrix<Real> & piola = *piola_it; Matrix<Real> & sigma = *stress_it; gradUToF<2>(grad_u, F_tensor); computeCauchyStressOnQuad<2>(F_tensor, piola, sigma, *c33_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialNeohookean<dim>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computeStressOnQuad(grad_u, sigma); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void MaterialNeohookean<2>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (this->plane_stress) { PlaneStressToolbox<2>::computeStress(el_type, ghost_type); Array<Real>::const_scalar_iterator c33_it = this->third_axis_deformation(el_type, ghost_type).begin(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computeStressOnQuad(grad_u, sigma, *c33_it); ++c33_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } else { MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computeStressOnQuad(grad_u, sigma); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialNeohookean<dim>::computeThirdAxisDeformation( ElementType /*el_type*/, GhostType /*ghost_type*/) {} /* -------------------------------------------------------------------------- */ template <> void MaterialNeohookean<2>::computeThirdAxisDeformation(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(this->plane_stress, "The third component of the strain " "can only be computed for 2D " "problems in Plane Stress!!"); Array<Real>::scalar_iterator c33_it = this->third_axis_deformation(el_type, ghost_type).begin(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computeThirdAxisDeformationOnQuad(grad_u, *c33_it); ++c33_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialNeohookean<spatial_dimension>::computePotentialEnergy( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Material::computePotentialEnergy(el_type, ghost_type); if (ghost_type != _not_ghost) return; Array<Real>::scalar_iterator epot = this->potential_energy(el_type, ghost_type).begin(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computePotentialEnergyOnQuad(grad_u, *epot); ++epot; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialNeohookean<spatial_dimension>::computeTangentModuli( __attribute__((unused)) const ElementType & el_type, Array<Real> & tangent_matrix, __attribute__((unused)) GhostType ghost_type) { AKANTU_DEBUG_IN(); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); computeTangentModuliOnQuad(tangent, grad_u); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void MaterialNeohookean<2>::computeTangentModuli(__attribute__((unused)) const ElementType & el_type, Array<Real> & tangent_matrix, __attribute__((unused)) GhostType ghost_type) { AKANTU_DEBUG_IN(); if (this->plane_stress) { PlaneStressToolbox<2>::computeStress(el_type, ghost_type); Array<Real>::const_scalar_iterator c33_it = this->third_axis_deformation(el_type, ghost_type).begin(); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); computeTangentModuliOnQuad(tangent, grad_u, *c33_it); ++c33_it; MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; } else { MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); computeTangentModuliOnQuad(tangent, grad_u); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialNeohookean<spatial_dimension>::getPushWaveSpeed( __attribute__((unused)) const Element & element) const { return sqrt((this->lambda + 2 * this->mu) / this->rho); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialNeohookean<spatial_dimension>::getShearWaveSpeed( __attribute__((unused)) const Element & element) const { return sqrt(this->mu / this->rho); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(neohookean, MaterialNeohookean); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh b/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh index 96d6b1b7c..77a934ded 100644 --- a/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh +++ b/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh @@ -1,169 +1,168 @@ /** * @file material_neohookean.hh * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 08 2015 + * @date last modification: Wed Nov 29 2017 * * @brief Material isotropic elastic * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "plane_stress_toolbox.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_NEOHOOKEAN_HH__ #define __AKANTU_MATERIAL_NEOHOOKEAN_HH__ namespace akantu { /** * Material elastic isotropic * * parameters in the material files : * - rho : density (default: 0) * - E : Young's modulus (default: 0) * - nu : Poisson's ratio (default: 1/2) * - Plane_Stress : if 0: plane strain, else: plane stress (default: 0) */ template <UInt spatial_dimension> class MaterialNeohookean : public PlaneStressToolbox<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialNeohookean(SolidMechanicsModel & model, const ID & id = ""); ~MaterialNeohookean() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter void initMaterial() override; /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// Computation of the cauchy stress for plane strain materials void computeCauchyStressPlaneStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// Non linear computation of the third direction strain in 2D plane stress /// case void computeThirdAxisDeformation(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the elastic potential energy void computePotentialEnergy(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the tangent stiffness matrix for an element type void computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost) override; /// compute the p-wave speed in the material Real getPushWaveSpeed(const Element & element) const override; /// compute the s-wave speed in the material Real getShearWaveSpeed(const Element & element) const override; protected: /// constitutive law for a given quadrature point inline void computePiolaKirchhoffOnQuad(const Matrix<Real> & E, Matrix<Real> & S); /// constitutive law for a given quadrature point (first piola) inline void computeFirstPiolaKirchhoffOnQuad(const Matrix<Real> & grad_u, const Matrix<Real> & S, Matrix<Real> & P); /// constitutive law for a given quadrature point inline void computeDeltaStressOnQuad(const Matrix<Real> & grad_u, const Matrix<Real> & grad_delta_u, Matrix<Real> & delta_S); /// constitutive law for a given quadrature point inline void computeStressOnQuad(Matrix<Real> & grad_u, Matrix<Real> & S, const Real & C33 = 1.0); /// constitutive law for a given quadrature point inline void computeThirdAxisDeformationOnQuad(Matrix<Real> & grad_u, Real & c33_value); /// constitutive law for a given quadrature point // inline void updateStressOnQuad(const Matrix<Real> & sigma, // Matrix<Real> & cauchy_sigma); /// compute the potential energy for a quadrature point inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u, Real & epot); /// compute the tangent stiffness matrix for an element void computeTangentModuliOnQuad(Matrix<Real> & tangent, Matrix<Real> & grad_u, const Real & C33 = 1.0); /// recompute the lame coefficient if E or nu changes void updateInternalParameters() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the young modulus Real E; /// Poisson coefficient Real nu; /// First Lamé coefficient Real lambda; /// Second Lamé coefficient (shear modulus) Real mu; /// Bulk modulus Real kpa; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_neohookean_inline_impl.cc" } // akantu #endif /* __AKANTU_MATERIAL_NEOHOOKEAN_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc b/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc index b99d4e14f..c46c352bb 100644 --- a/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc @@ -1,191 +1,191 @@ /** * @file material_neohookean_inline_impl.cc * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * * @date creation: Mon Apr 08 2013 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief Implementation of the inline functions of the material elastic * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #include <iostream> #include "material_neohookean.hh" #include <cmath> #include <utility> /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialNeohookean<dim>::computeDeltaStressOnQuad( __attribute__((unused)) const Matrix<Real> & grad_u, __attribute__((unused)) const Matrix<Real> & grad_delta_u, __attribute__((unused)) Matrix<Real> & delta_S) {} //! computes the second piola kirchhoff stress, called S template <UInt dim> inline void MaterialNeohookean<dim>::computeStressOnQuad(Matrix<Real> & grad_u, Matrix<Real> & S, const Real & C33) { // Neo hookean book Matrix<Real> F(dim, dim); Matrix<Real> C(dim, dim); // Right green Matrix<Real> Cminus(dim, dim); // Right green this->template gradUToF<dim>(grad_u, F); this->rightCauchy(F, C); Real J = F.det() * sqrt(C33); // the term sqrt(C33) corresponds to the off // plane strain (2D plane stress) // std::cout<<"det(F) -> "<<J<<std::endl; Cminus.inverse(C); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) S(i, j) = (i == j) * mu + (lambda * log(J) - mu) * Cminus(i, j); } /* -------------------------------------------------------------------------- */ class C33_NR : public Math::NewtonRaphsonFunctor { public: C33_NR(std::string name, const Real & lambda, const Real & mu, const Matrix<Real> & C) : NewtonRaphsonFunctor(std::move(name)), lambda(lambda), mu(mu), C(C) {} inline Real f(Real x) const override { return (this->lambda / 2. * (std::log(x) + std::log(this->C(0, 0) * this->C(1, 1) - Math::pow<2>(this->C(0, 1)))) + this->mu * (x - 1.)); } inline Real f_prime(Real x) const override { AKANTU_DEBUG_ASSERT(std::abs(x) > Math::getTolerance(), "x is zero (x should be the off plane right Cauchy" << " measure in this function so you made a mistake" << " somewhere else that lead to a zero here!!!"); return (this->lambda / (2. * x) + this->mu); } private: const Real & lambda; const Real & mu; const Matrix<Real> & C; }; /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialNeohookean<dim>::computeThirdAxisDeformationOnQuad( Matrix<Real> & grad_u, Real & c33_value) { // Neo hookean book Matrix<Real> F(dim, dim); Matrix<Real> C(dim, dim); // Right green this->template gradUToF<dim>(grad_u, F); this->rightCauchy(F, C); Math::NewtonRaphson nr(1e-5, 100); c33_value = nr.solve( C33_NR("Neohookean_plan_stress", this->lambda, this->mu, C), c33_value); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialNeohookean<dim>::computePiolaKirchhoffOnQuad(const Matrix<Real> & E, Matrix<Real> & S) { Real trace = E.trace(); /// trace = (\nabla u)_{kk} /// \sigma_{ij} = \lambda * (\nabla u)_{kk} * \delta_{ij} + \mu * (\nabla /// u_{ij} + \nabla u_{ji}) for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) S(i, j) = (i == j) * lambda * trace + 2.0 * mu * E(i, j); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialNeohookean<dim>::computeFirstPiolaKirchhoffOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & S, Matrix<Real> & P) { Matrix<Real> F(dim, dim); Matrix<Real> C(dim, dim); // Right green this->template gradUToF<dim>(grad_u, F); // first Piola-Kirchhoff is computed as the product of the deformation // gracient // tensor and the second Piola-Kirchhoff stress tensor P = F * S; } /**************************************************************************************/ /* Computation of the potential energy for a this neo hookean material */ template <UInt dim> inline void MaterialNeohookean<dim>::computePotentialEnergyOnQuad( const Matrix<Real> & grad_u, Real & epot) { Matrix<Real> F(dim, dim); Matrix<Real> C(dim, dim); // Right green this->template gradUToF<dim>(grad_u, F); this->rightCauchy(F, C); Real J = F.det(); // std::cout<<"det(F) -> "<<J<<std::endl; epot = 0.5 * lambda * pow(log(J), 2.) + mu * (-log(J) + 0.5 * (C.trace() - dim)); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialNeohookean<dim>::computeTangentModuliOnQuad( Matrix<Real> & tangent, Matrix<Real> & grad_u, const Real & C33) { // Neo hookean book UInt cols = tangent.cols(); UInt rows = tangent.rows(); Matrix<Real> F(dim, dim); Matrix<Real> C(dim, dim); Matrix<Real> Cminus(dim, dim); this->template gradUToF<dim>(grad_u, F); this->rightCauchy(F, C); Real J = F.det() * sqrt(C33); // std::cout<<"det(F) -> "<<J<<std::endl; Cminus.inverse(C); for (UInt m = 0; m < rows; m++) { UInt i = VoigtHelper<dim>::vec[m][0]; UInt j = VoigtHelper<dim>::vec[m][1]; for (UInt n = 0; n < cols; n++) { UInt k = VoigtHelper<dim>::vec[n][0]; UInt l = VoigtHelper<dim>::vec[n][1]; // book belytchko tangent(m, n) = lambda * Cminus(i, j) * Cminus(k, l) + (mu - lambda * log(J)) * (Cminus(i, k) * Cminus(j, l) + Cminus(i, l) * Cminus(k, j)); } } } /* -------------------------------------------------------------------------- */ diff --git a/src/model/solid_mechanics/materials/material_non_local.hh b/src/model/solid_mechanics/materials/material_non_local.hh index acff2d771..763a06ae4 100644 --- a/src/model/solid_mechanics/materials/material_non_local.hh +++ b/src/model/solid_mechanics/materials/material_non_local.hh @@ -1,120 +1,119 @@ /** * @file material_non_local.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Mon Sep 11 2017 * * @brief Material class that handle the non locality of a law for example * damage. * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_NON_LOCAL_HH__ #define __AKANTU_MATERIAL_NON_LOCAL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ class MaterialNonLocalInterface { /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material the non local parts of the material void initMaterialNonLocal() { this->registerNeighborhood(); this->registerNonLocalVariables(); }; /// insert the quadrature points in the neighborhoods of the non-local manager virtual void insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type, const ElementTypeMapReal & quadrature_points_coordinates) = 0; /// update the values in the non-local internal fields virtual void updateNonLocalInternals(ElementTypeMapReal & non_local_flattened, const ID & field_id, const GhostType & ghost_type, const ElementKind & kind) = 0; /// constitutive law virtual void computeNonLocalStresses(GhostType ghost_type = _not_ghost) = 0; protected: /// get the name of the neighborhood for this material virtual ID getNeighborhoodName() = 0; /// register the neighborhoods for the material virtual void registerNeighborhood() = 0; /// register the non local internal variable virtual void registerNonLocalVariables() = 0; virtual inline void onElementsAdded(const Array<Element> &, const NewElementsEvent &) {} }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <UInt dim, class LocalParent> class MaterialNonLocal : public MaterialNonLocalInterface, public LocalParent { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit MaterialNonLocal(SolidMechanicsModel & model, const ID & id); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// insert the quadrature points in the neighborhoods of the non-local manager void insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type, const ElementTypeMapReal & quadrature_points_coordinates) override; /// update the values in the non-local internal fields void updateNonLocalInternals(ElementTypeMapReal & non_local_flattened, const ID & field_id, const GhostType & ghost_type, const ElementKind & kind) override; /// register the neighborhoods for the material void registerNeighborhood() override; protected: /// get the name of the neighborhood for this material ID getNeighborhoodName() override { return this->name; } }; } // namespace akantu /* -------------------------------------------------------------------------- */ #include "material_non_local_tmpl.hh" #endif /* __AKANTU_MATERIAL_NON_LOCAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_non_local_includes.hh b/src/model/solid_mechanics/materials/material_non_local_includes.hh index d3b20179f..4a0c657be 100644 --- a/src/model/solid_mechanics/materials/material_non_local_includes.hh +++ b/src/model/solid_mechanics/materials/material_non_local_includes.hh @@ -1,40 +1,39 @@ /** * @file material_non_local_includes.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Oct 31 2012 - * @date last modification: Wed Nov 18 2015 + * @date last modification: Thu Jul 06 2017 * * @brief Non local materials includes * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_CMAKE_LIST_MATERIALS #include "material_marigo_non_local.hh" #include "material_mazars_non_local.hh" #endif #define AKANTU_DAMAGE_NON_LOCAL_MATERIAL_LIST \ ((2, (marigo_non_local, MaterialMarigoNonLocal)))( \ (2, (mazars_non_local, MaterialMazarsNonLocal))) diff --git a/src/model/solid_mechanics/materials/material_non_local_tmpl.hh b/src/model/solid_mechanics/materials/material_non_local_tmpl.hh index ccfd93508..de6046f3c 100644 --- a/src/model/solid_mechanics/materials/material_non_local_tmpl.hh +++ b/src/model/solid_mechanics/materials/material_non_local_tmpl.hh @@ -1,128 +1,128 @@ /** - * @file material_non_local.cc + * @file material_non_local_tmpl.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Sat Sep 26 2015 - * @date last modification: Tue Dec 08 2015 + * @date creation: Thu Jul 06 2017 + * @date last modification: Tue Nov 07 2017 * * @brief Implementation of material non-local * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "material_non_local.hh" #include "non_local_neighborhood.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim, class LocalParent> MaterialNonLocal<dim, LocalParent>::MaterialNonLocal( SolidMechanicsModel & model, const ID & id) : LocalParent(model, id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim, class LocalParent> void MaterialNonLocal<dim, LocalParent>::insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type, const ElementTypeMapReal & quadrature_points_coordinates) { IntegrationPoint q; q.ghost_type = ghost_type; auto & neighborhood = this->model.getNonLocalManager().getNeighborhood( this->getNeighborhoodName()); for (auto & type : this->element_filter.elementTypes(dim, ghost_type, _ek_regular)) { q.type = type; const auto & elem_filter = this->element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element) { UInt nb_quad = this->getFEEngine().getNbIntegrationPoints(type, ghost_type); const auto & quads = quadrature_points_coordinates(type, ghost_type); auto nb_total_element = this->model.getMesh().getNbElement(type, ghost_type); auto quads_it = quads.begin_reinterpret(dim, nb_quad, nb_total_element); for (auto & elem : elem_filter) { Matrix<Real> quads = quads_it[elem]; q.element = elem; for (UInt nq = 0; nq < nb_quad; ++nq) { q.num_point = nq; q.global_num = q.element * nb_quad + nq; neighborhood.insertIntegrationPoint(q, quads(nq)); } } } } } /* -------------------------------------------------------------------------- */ template <UInt dim, class LocalParent> void MaterialNonLocal<dim, LocalParent>::updateNonLocalInternals( ElementTypeMapReal & non_local_flattened, const ID & field_id, const GhostType & ghost_type, const ElementKind & kind) { /// loop over all types in the material for (auto & el_type : this->element_filter.elementTypes(dim, ghost_type, kind)) { Array<Real> & internal = this->template getInternal<Real>(field_id)(el_type, ghost_type); auto & internal_flat = non_local_flattened(el_type, ghost_type); auto nb_component = internal_flat.getNbComponent(); auto internal_it = internal.begin(nb_component); auto internal_flat_it = internal_flat.begin(nb_component); /// loop all elements for the given type const auto & filter = this->element_filter(el_type, ghost_type); UInt nb_quads = this->getFEEngine().getNbIntegrationPoints(el_type, ghost_type); for (auto & elem : filter) { for (UInt q = 0; q < nb_quads; ++q, ++internal_it) { UInt global_quad = elem * nb_quads + q; *internal_it = internal_flat_it[global_quad]; } } } } /* -------------------------------------------------------------------------- */ template <UInt dim, class LocalParent> void MaterialNonLocal<dim, LocalParent>::registerNeighborhood() { ID name = this->getNeighborhoodName(); this->model.getNonLocalManager().registerNeighborhood(name, name); } } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc index d5db9fa1a..0e287d59c 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc @@ -1,201 +1,202 @@ /** * @file material_linear_isotropic_hardening.cc * * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Benjamin Paccaud <benjamin.paccaud@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Apr 07 2014 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Sat Dec 02 2017 * * @brief Specialization of the material class for isotropic finite deformation * linear hardening plasticity * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_linear_isotropic_hardening.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim> MaterialLinearIsotropicHardening<dim>::MaterialLinearIsotropicHardening( SolidMechanicsModel & model, const ID & id) : MaterialPlastic<dim>(model, id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialLinearIsotropicHardening<spatial_dimension>:: MaterialLinearIsotropicHardening(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : MaterialPlastic<spatial_dimension>(model, dim, mesh, fe_engine, id) {} /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialLinearIsotropicHardening<spatial_dimension>::computeStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialThermal<spatial_dimension>::computeStress(el_type, ghost_type); // infinitesimal and finite deformation auto sigma_th_it = this->sigma_th(el_type, ghost_type).begin(); auto previous_sigma_th_it = this->sigma_th.previous(el_type, ghost_type).begin(); auto previous_gradu_it = this->gradu.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto previous_stress_it = this->stress.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto inelastic_strain_it = this->inelastic_strain(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto previous_inelastic_strain_it = this->inelastic_strain.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto iso_hardening_it = this->iso_hardening(el_type, ghost_type).begin(); auto previous_iso_hardening_it = this->iso_hardening.previous(el_type, ghost_type).begin(); // // Finite Deformations // if (this->finite_deformation) { auto previous_piola_kirchhoff_2_it = this->piola_kirchhoff_2.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto green_strain_it = this->green_strain(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); auto & inelastic_strain_tensor = *inelastic_strain_it; auto & previous_inelastic_strain_tensor = *previous_inelastic_strain_it; auto & previous_grad_u = *previous_gradu_it; auto & previous_sigma = *previous_piola_kirchhoff_2_it; auto & green_strain = *green_strain_it; this->template gradUToGreenStrain<spatial_dimension>(grad_u, green_strain); Matrix<Real> previous_green_strain(spatial_dimension, spatial_dimension); this->template gradUToGreenStrain<spatial_dimension>(previous_grad_u, previous_green_strain); Matrix<Real> F_tensor(spatial_dimension, spatial_dimension); this->template gradUToF<spatial_dimension>(grad_u, F_tensor); computeStressOnQuad(green_strain, previous_green_strain, sigma, previous_sigma, inelastic_strain_tensor, previous_inelastic_strain_tensor, *iso_hardening_it, *previous_iso_hardening_it, *sigma_th_it, *previous_sigma_th_it, F_tensor); ++sigma_th_it; ++inelastic_strain_it; ++iso_hardening_it; ++previous_sigma_th_it; //++previous_stress_it; ++previous_gradu_it; ++green_strain_it; ++previous_inelastic_strain_it; ++previous_iso_hardening_it; ++previous_piola_kirchhoff_2_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } // Infinitesimal deformations else { MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); auto & inelastic_strain_tensor = *inelastic_strain_it; auto & previous_inelastic_strain_tensor = *previous_inelastic_strain_it; auto & previous_grad_u = *previous_gradu_it; auto & previous_sigma = *previous_stress_it; computeStressOnQuad( grad_u, previous_grad_u, sigma, previous_sigma, inelastic_strain_tensor, previous_inelastic_strain_tensor, *iso_hardening_it, *previous_iso_hardening_it, *sigma_th_it, *previous_sigma_th_it); ++sigma_th_it; ++inelastic_strain_it; ++iso_hardening_it; ++previous_sigma_th_it; ++previous_stress_it; ++previous_gradu_it; ++previous_inelastic_strain_it; ++previous_iso_hardening_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialLinearIsotropicHardening<spatial_dimension>::computeTangentModuli( const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto previous_gradu_it = this->gradu.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto previous_stress_it = this->stress.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto iso_hardening = this->iso_hardening(el_type, ghost_type).begin(); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); computeTangentModuliOnQuad(tangent, grad_u, *previous_gradu_it, sigma_tensor, *previous_stress_it, *iso_hardening); ++previous_gradu_it; ++previous_stress_it; ++iso_hardening; MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; this->was_stiffness_assembled = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(plastic_linear_isotropic_hardening, MaterialLinearIsotropicHardening); } // akantu diff --git a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh index 78aa000cd..dea48f6b9 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh +++ b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh @@ -1,113 +1,113 @@ /** * @file material_linear_isotropic_hardening.hh * * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Benjamin Paccaud <benjamin.paccaud@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Mon Jun 01 2015 + * @date last modification: Sat Dec 02 2017 * * @brief Specialization of the material class for isotropic finite deformation * linear hardening plasticity * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_voigthelper.hh" #include "material_plastic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_LINEAR_ISOTROPIC_HARDENING_HH__ #define __AKANTU_MATERIAL_LINEAR_ISOTROPIC_HARDENING_HH__ namespace akantu { /** * Material plastic with a linear evolution of the yielding stress */ template <UInt spatial_dimension> class MaterialLinearIsotropicHardening : public MaterialPlastic<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialLinearIsotropicHardening(SolidMechanicsModel & model, const ID & id = ""); MaterialLinearIsotropicHardening(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the tangent stiffness matrix for an element type void computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost) override; protected: /// Infinitesimal deformations inline void computeStressOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelas_strain, const Matrix<Real> & previous_inelas_strain, Real & iso_hardening, const Real & previous_iso_hardening, const Real & sigma_th, const Real & previous_sigma_th); /// Finite deformations inline void computeStressOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelas_strain, const Matrix<Real> & previous_inelas_strain, Real & iso_hardening, const Real & previous_iso_hardening, const Real & sigma_th, const Real & previous_sigma_th, const Matrix<Real> & F_tensor); inline void computeTangentModuliOnQuad( Matrix<Real> & tangent, const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, const Matrix<Real> & sigma_tensor, const Matrix<Real> & previous_sigma_tensor, const Real & iso_hardening) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ } // akantu #include "material_linear_isotropic_hardening_inline_impl.cc" #endif /* __AKANTU_MATERIAL_LINEAR_ISOTROPIC_HARDENING_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc index 8fb7dbff4..06bb421f4 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc @@ -1,297 +1,298 @@ /** * @file material_linear_isotropic_hardening_inline_impl.cc * * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Benjamin Paccaud <benjamin.paccaud@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Apr 07 2014 - * @date last modification: Fri May 29 2015 + * @date last modification: Thu Nov 30 2017 * * @brief Implementation of the inline functions of the material plasticity * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ #include "material_linear_isotropic_hardening.hh" namespace akantu { /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /// Infinitesimal deformations template <UInt dim> inline void MaterialLinearIsotropicHardening<dim>::computeStressOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelastic_strain, const Matrix<Real> & previous_inelastic_strain, Real & iso_hardening, const Real & previous_iso_hardening, const Real & sigma_th, const Real & previous_sigma_th) { Real delta_sigma_th = sigma_th - previous_sigma_th; Matrix<Real> grad_delta_u(grad_u); grad_delta_u -= previous_grad_u; // Compute trial stress, sigma_tr Matrix<Real> sigma_tr(dim, dim); MaterialElastic<dim>::computeStressOnQuad(grad_delta_u, sigma_tr, delta_sigma_th); sigma_tr += previous_sigma; // We need a full stress tensor, otherwise the VM stress is messed up Matrix<Real> sigma_tr_dev(3, 3, 0); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) sigma_tr_dev(i, j) = sigma_tr(i, j); sigma_tr_dev -= Matrix<Real>::eye(3, sigma_tr.trace() / 3.0); // Compute effective deviatoric trial stress Real s = sigma_tr_dev.doubleDot(sigma_tr_dev); Real sigma_tr_dev_eff = std::sqrt(3. / 2. * s); bool initial_yielding = ((sigma_tr_dev_eff - iso_hardening - this->sigma_y) > 0); Real dp = (initial_yielding) ? (sigma_tr_dev_eff - this->sigma_y - previous_iso_hardening) / (3 * this->mu + this->h) : 0; iso_hardening = previous_iso_hardening + this->h * dp; // Compute inelastic strain (ignore last components in 1-2D) Matrix<Real> delta_inelastic_strain(dim, dim, 0.); if (std::abs(sigma_tr_dev_eff) > sigma_tr_dev.norm<L_inf>() * Math::getTolerance()) { for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) delta_inelastic_strain(i, j) = sigma_tr_dev(i, j); delta_inelastic_strain *= 3. / 2. * dp / sigma_tr_dev_eff; } MaterialPlastic<dim>::computeStressAndInelasticStrainOnQuad( grad_delta_u, sigma, previous_sigma, inelastic_strain, previous_inelastic_strain, delta_inelastic_strain); } /* -------------------------------------------------------------------------- */ /// Finite deformations template <UInt dim> inline void MaterialLinearIsotropicHardening<dim>::computeStressOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelastic_strain, const Matrix<Real> & previous_inelastic_strain, Real & iso_hardening, const Real & previous_iso_hardening, const Real & sigma_th, const Real & previous_sigma_th, const Matrix<Real> & F_tensor) { // Finite plasticity Real dp = 0.0; Real d_dp = 0.0; UInt n = 0; Real delta_sigma_th = sigma_th - previous_sigma_th; Matrix<Real> grad_delta_u(grad_u); grad_delta_u -= previous_grad_u; // Compute trial stress, sigma_tr Matrix<Real> sigma_tr(dim, dim); MaterialElastic<dim>::computeStressOnQuad(grad_delta_u, sigma_tr, delta_sigma_th); sigma_tr += previous_sigma; // Compute deviatoric trial stress, sigma_tr_dev Matrix<Real> sigma_tr_dev(sigma_tr); sigma_tr_dev -= Matrix<Real>::eye(dim, sigma_tr.trace() / 3.0); // Compute effective deviatoric trial stress Real s = sigma_tr_dev.doubleDot(sigma_tr_dev); Real sigma_tr_dev_eff = std::sqrt(3. / 2. * s); // compute the cauchy stress to apply the Von-Mises criterion Matrix<Real> cauchy_stress(dim, dim); Material::computeCauchyStressOnQuad<dim>(F_tensor, sigma_tr, cauchy_stress); Matrix<Real> cauchy_stress_dev(cauchy_stress); cauchy_stress_dev -= Matrix<Real>::eye(dim, cauchy_stress.trace() / 3.0); Real c = cauchy_stress_dev.doubleDot(cauchy_stress_dev); Real cauchy_stress_dev_eff = std::sqrt(3. / 2. * c); const Real iso_hardening_t = previous_iso_hardening; iso_hardening = iso_hardening_t; // Loop for correcting stress based on yield function // F is written in terms of S // bool initial_yielding = ( (sigma_tr_dev_eff - iso_hardening - // this->sigma_y) > 0) ; // while ( initial_yielding && std::abs(sigma_tr_dev_eff - iso_hardening - // this->sigma_y) > Math::getTolerance() ) { // d_dp = (sigma_tr_dev_eff - 3. * this->mu *dp - iso_hardening - // this->sigma_y) // / (3. * this->mu + this->h); // //r = r + h * dp; // dp = dp + d_dp; // iso_hardening = iso_hardening_t + this->h * dp; // ++n; // /// TODO : explicit this criterion with an error message // if ((std::abs(d_dp) < 1e-9) || (n>50)){ // AKANTU_DEBUG_INFO("convergence of increment of plastic strain. d_dp:" // << d_dp << "\tNumber of iteration:"<<n); // break; // } // } // F is written in terms of cauchy stress bool initial_yielding = ((cauchy_stress_dev_eff - iso_hardening - this->sigma_y) > 0); while (initial_yielding && std::abs(cauchy_stress_dev_eff - iso_hardening - this->sigma_y) > Math::getTolerance()) { d_dp = (cauchy_stress_dev_eff - 3. * this->mu * dp - iso_hardening - this->sigma_y) / (3. * this->mu + this->h); // r = r + h * dp; dp = dp + d_dp; iso_hardening = iso_hardening_t + this->h * dp; ++n; /// TODO : explicit this criterion with an error message if ((d_dp < 1e-5) || (n > 50)) { AKANTU_DEBUG_INFO("convergence of increment of plastic strain. d_dp:" << d_dp << "\tNumber of iteration:" << n); break; } } // Update internal variable Matrix<Real> delta_inelastic_strain(dim, dim, 0.); if (std::abs(sigma_tr_dev_eff) > sigma_tr_dev.norm<L_inf>() * Math::getTolerance()) { // /// compute the direction of the plastic strain as \frac{\partial // F}{\partial S} = \frac{3}{2J\sigma_{effective}}} Ft \sigma_{dev} F Matrix<Real> cauchy_dev_F(dim, dim); cauchy_dev_F.mul<false, false>(F_tensor, cauchy_stress_dev); Real J = F_tensor.det(); Real constant = J ? 1. / J : 0; constant *= 3. * dp / (2. * cauchy_stress_dev_eff); delta_inelastic_strain.mul<true, false>(F_tensor, cauchy_dev_F, constant); // Direction given by the piola kirchhoff deviatoric tensor \frac{\partial // F}{\partial S} = \frac{3}{2\sigma_{effective}}}S_{dev} // delta_inelastic_strain.copy(sigma_tr_dev); // delta_inelastic_strain *= 3./2. * dp / sigma_tr_dev_eff; } MaterialPlastic<dim>::computeStressAndInelasticStrainOnQuad( grad_delta_u, sigma, previous_sigma, inelastic_strain, previous_inelastic_strain, delta_inelastic_strain); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialLinearIsotropicHardening<dim>::computeTangentModuliOnQuad( Matrix<Real> & tangent, __attribute__((unused)) const Matrix<Real> & grad_u, __attribute__((unused)) const Matrix<Real> & previous_grad_u, __attribute__((unused)) const Matrix<Real> & sigma_tensor, __attribute__((unused)) const Matrix<Real> & previous_sigma_tensor, __attribute__((unused)) const Real & iso_hardening) const { // Real r=iso_hardening; // Matrix<Real> grad_delta_u(grad_u); // grad_delta_u -= previous_grad_u; // //Compute trial stress, sigma_tr // Matrix<Real> sigma_tr(dim, dim); // MaterialElastic<dim>::computeStressOnQuad(grad_delta_u, sigma_tr); // sigma_tr += previous_sigma_tensor; // // Compute deviatoric trial stress, sigma_tr_dev // Matrix<Real> sigma_tr_dev(sigma_tr); // sigma_tr_dev -= Matrix<Real>::eye(dim, sigma_tr.trace() / 3.0); // // Compute effective deviatoric trial stress // Real s = sigma_tr_dev.doubleDot(sigma_tr_dev); // Real sigma_tr_dev_eff=std::sqrt(3./2. * s); // // Compute deviatoric stress, sigma_dev // Matrix<Real> sigma_dev(sigma_tensor); // sigma_dev -= Matrix<Real>::eye(dim, sigma_tensor.trace() / 3.0); // // Compute effective deviatoric stress // s = sigma_dev.doubleDot(sigma_dev); // Real sigma_dev_eff = std::sqrt(3./2. * s); // Real xr = 0.0; // if(sigma_tr_dev_eff > sigma_dev_eff * Math::getTolerance()) // xr = sigma_dev_eff / sigma_tr_dev_eff; // Real __attribute__((unused)) q = 1.5 * (1. / (1. + 3. * this->mu / // this->h) - xr); /* UInt cols = tangent.cols(); UInt rows = tangent.rows(); for (UInt m = 0; m < rows; ++m) { UInt i = VoigtHelper<dim>::vec[m][0]; UInt j = VoigtHelper<dim>::vec[m][1]; for (UInt n = 0; n < cols; ++n) { UInt k = VoigtHelper<dim>::vec[n][0]; UInt l = VoigtHelper<dim>::vec[n][1]; */ // This section of the code is commented // There were some problems with the convergence of plastic-coupled // simulations with thermal expansion // XXX: DO NOT REMOVE /*if (((sigma_tr_dev_eff-iso_hardening-sigmay) > 0) && (xr > 0)) { tangent(m,n) = 2. * this->mu * q * (sigma_tr_dev (i,j) / sigma_tr_dev_eff) * (sigma_tr_dev (k,l) / sigma_tr_dev_eff) + (i==k) * (j==l) * 2. * this->mu * xr + (i==j) * (k==l) * (this->kpa - 2./3. * this->mu * xr); if ((m == n) && (m>=dim)) tangent(m, n) = tangent(m, n) - this->mu * xr; } else {*/ /* tangent(m,n) = (i==k) * (j==l) * 2. * this->mu + (i==j) * (k==l) * this->lambda; tangent(m,n) -= (m==n) * (m>=dim) * this->mu; */ //} // correct tangent stiffness for shear component //} //} MaterialElastic<dim>::computeTangentModuliOnQuad(tangent); } } // akantu diff --git a/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc b/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc index bfe07f012..1032eab13 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc @@ -1,209 +1,209 @@ /** * @file material_plastic.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Apr 07 2014 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Implemantation of the akantu::MaterialPlastic class * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_plastic.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialPlastic<spatial_dimension>::MaterialPlastic(SolidMechanicsModel & model, const ID & id) : MaterialElastic<spatial_dimension>(model, id), iso_hardening("iso_hardening", *this), inelastic_strain("inelastic_strain", *this), plastic_energy("plastic_energy", *this), d_plastic_energy("d_plastic_energy", *this) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } template <UInt spatial_dimension> MaterialPlastic<spatial_dimension>::MaterialPlastic(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : MaterialElastic<spatial_dimension>(model, dim, mesh, fe_engine, id), iso_hardening("iso_hardening", *this, dim, fe_engine, this->element_filter), inelastic_strain("inelastic_strain", *this, dim, fe_engine, this->element_filter), plastic_energy("plastic_energy", *this, dim, fe_engine, this->element_filter), d_plastic_energy("d_plastic_energy", *this, dim, fe_engine, this->element_filter) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialPlastic<spatial_dimension>::initialize() { this->registerParam("h", h, Real(0.), _pat_parsable | _pat_modifiable, "Hardening modulus"); this->registerParam("sigma_y", sigma_y, Real(0.), _pat_parsable | _pat_modifiable, "Yield stress"); this->iso_hardening.initialize(1); this->iso_hardening.initializeHistory(); this->plastic_energy.initialize(1); this->d_plastic_energy.initialize(1); this->use_previous_stress = true; this->use_previous_gradu = true; this->use_previous_stress_thermal = true; this->inelastic_strain.initialize(spatial_dimension * spatial_dimension); this->inelastic_strain.initializeHistory(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialPlastic<spatial_dimension>::getEnergy(const std::string & type) { if (type == "plastic") return getPlasticEnergy(); else return MaterialElastic<spatial_dimension>::getEnergy(type); return 0.; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialPlastic<spatial_dimension>::getPlasticEnergy() { AKANTU_DEBUG_IN(); Real penergy = 0.; for (auto & type : this->element_filter.elementTypes(spatial_dimension, _not_ghost)) { penergy += this->fem.integrate(plastic_energy(type, _not_ghost), type, _not_ghost, this->element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return penergy; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialPlastic<spatial_dimension>::computePotentialEnergy( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (ghost_type != _not_ghost) return; Array<Real>::scalar_iterator epot = this->potential_energy(el_type, ghost_type).begin(); Array<Real>::const_iterator<Matrix<Real>> inelastic_strain_it = this->inelastic_strain(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> elastic_strain(spatial_dimension, spatial_dimension); elastic_strain.copy(grad_u); elastic_strain -= *inelastic_strain_it; MaterialElastic<spatial_dimension>::computePotentialEnergyOnQuad( elastic_strain, sigma, *epot); ++epot; ++inelastic_strain_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialPlastic<spatial_dimension>::updateEnergies(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialElastic<spatial_dimension>::updateEnergies(el_type, ghost_type); Array<Real>::iterator<> pe_it = this->plastic_energy(el_type, ghost_type).begin(); Array<Real>::iterator<> wp_it = this->d_plastic_energy(el_type, ghost_type).begin(); Array<Real>::iterator<Matrix<Real>> inelastic_strain_it = this->inelastic_strain(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); Array<Real>::iterator<Matrix<Real>> previous_inelastic_strain_it = this->inelastic_strain.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator previous_sigma = this->stress.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> delta_strain_it(*inelastic_strain_it); delta_strain_it -= *previous_inelastic_strain_it; Matrix<Real> sigma_h(sigma); sigma_h += *previous_sigma; *wp_it = .5 * sigma_h.doubleDot(delta_strain_it); *pe_it += *wp_it; ++pe_it; ++wp_it; ++inelastic_strain_it; ++previous_inelastic_strain_it; ++previous_sigma; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL_ONLY(MaterialPlastic); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_plastic/material_plastic.hh b/src/model/solid_mechanics/materials/material_plastic/material_plastic.hh index 1b1b2749b..36ac049c8 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_plastic.hh +++ b/src/model/solid_mechanics/materials/material_plastic/material_plastic.hh @@ -1,130 +1,130 @@ /** * @file material_plastic.hh * + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 08 2015 + * @date last modification: Thu Dec 07 2017 * * @brief Common interface for plastic materials * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_PLASTIC_HH__ #define __AKANTU_MATERIAL_PLASTIC_HH__ namespace akantu { /** * Parent class for the plastic constitutive laws * parameters in the material files : * - h : Hardening parameter (default: 0) * - sigmay : Yield stress */ template <UInt dim> class MaterialPlastic : public MaterialElastic<dim> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialPlastic(SolidMechanicsModel & model, const ID & id = ""); MaterialPlastic(SolidMechanicsModel & model, UInt a_dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get the energy specifying the type for the time step Real getEnergy(const std::string & type) override; /// Compute the plastic energy void updateEnergies(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// Compute the true potential energy void computePotentialEnergy(ElementType el_type, GhostType ghost_type) override; protected: /// compute the stress and inelastic strain for the quadrature point inline void computeStressAndInelasticStrainOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelas_strain, const Matrix<Real> & previous_inelas_strain, const Matrix<Real> & delta_inelastic_strain) const; inline void computeStressAndInelasticStrainOnQuad( const Matrix<Real> & delta_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelas_strain, const Matrix<Real> & previous_inelas_strain, const Matrix<Real> & delta_inelastic_strain) const; /// get the plastic energy for the time step Real getPlasticEnergy(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Yield stresss Real sigma_y; /// hardening modulus Real h; /// isotropic hardening, r InternalField<Real> iso_hardening; /// inelastic strain arrays ordered by element types (inelastic deformation) InternalField<Real> inelastic_strain; /// Plastic energy InternalField<Real> plastic_energy; /// @todo : add a coefficient beta that will multiply the plastic energy /// increment /// to compute the energy converted to heat /// Plastic energy increment InternalField<Real> d_plastic_energy; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ } // akantu #include "material_plastic_inline_impl.cc" #endif /* __AKANTU_MATERIAL_PLASTIC_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc b/src/model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc index 1c8172c80..f70afb3a2 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc @@ -1,75 +1,76 @@ /** * @file material_plastic_inline_impl.cc * + * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Apr 07 2014 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Wed Jan 24 2018 * * @brief Implementation of the inline functions of akantu::MaterialPlastic * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef MATERIAL_PLASTIC_INLINE_IMPL_H #define MATERIAL_PLASTIC_INLINE_IMPL_H #include "material_plastic.hh" namespace akantu { template <UInt dim> inline void MaterialPlastic<dim>::computeStressAndInelasticStrainOnQuad( const Matrix<Real> & delta_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelastic_strain, const Matrix<Real> & previous_inelastic_strain, const Matrix<Real> & delta_inelastic_strain) const { Matrix<Real> grad_u_elastic(dim, dim); grad_u_elastic.copy(delta_grad_u); grad_u_elastic -= delta_inelastic_strain; Matrix<Real> sigma_elastic(dim, dim); MaterialElastic<dim>::computeStressOnQuad(grad_u_elastic, sigma_elastic); sigma.copy(previous_sigma); sigma += sigma_elastic; inelastic_strain.copy(previous_inelastic_strain); inelastic_strain += delta_inelastic_strain; } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialPlastic<dim>::computeStressAndInelasticStrainOnQuad( const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelastic_strain, const Matrix<Real> & previous_inelastic_strain, const Matrix<Real> & delta_inelastic_strain) const { Matrix<Real> delta_grad_u(grad_u); delta_grad_u -= previous_grad_u; computeStressAndInelasticStrainOnQuad( delta_grad_u, sigma, previous_sigma, inelastic_strain, previous_inelastic_strain, delta_inelastic_strain); } } // Akantu #endif /* MATERIAL_PLASTIC_INLINE_IMPL_H */ diff --git a/src/model/solid_mechanics/materials/material_python/material_python.cc b/src/model/solid_mechanics/materials/material_python/material_python.cc index 3c3087c87..c48b3ae85 100644 --- a/src/model/solid_mechanics/materials/material_python/material_python.cc +++ b/src/model/solid_mechanics/materials/material_python/material_python.cc @@ -1,214 +1,215 @@ /** * @file material_python.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Nov 13 2015 - * @date last modification: Fri Nov 13 2015 + * @date last modification: Wed Feb 07 2018 * * @brief Material python implementation * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_python.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MaterialPython::MaterialPython(SolidMechanicsModel & model, PyObject * obj, const ID & id) : Material(model, id), PythonFunctor(obj) { AKANTU_DEBUG_IN(); this->registerInternals(); std::vector<std::string> param_names = this->callFunctor<std::vector<std::string>>("registerParam"); for (UInt i = 0; i < param_names.size(); ++i) { std::stringstream sstr; sstr << "PythonParameter" << i; this->registerParam(param_names[i], local_params[param_names[i]], 0., _pat_parsable | _pat_readable, sstr.str()); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialPython::registerInternals() { std::vector<std::string> internal_names = this->callFunctor<std::vector<std::string>>("registerInternals"); std::vector<UInt> internal_sizes; try { internal_sizes = this->callFunctor<std::vector<UInt>>("registerInternalSizes"); } catch (...) { internal_sizes.assign(internal_names.size(), 1); } for (UInt i = 0; i < internal_names.size(); ++i) { std::stringstream sstr; sstr << "PythonInternal" << i; this->internals[internal_names[i]] = std::make_unique<InternalField<Real>>(internal_names[i], *this); AKANTU_DEBUG_INFO("alloc internal " << internal_names[i] << " " << &this->internals[internal_names[i]]); this->internals[internal_names[i]]->initialize(internal_sizes[i]); } // making an internal with the quadrature points coordinates this->internals["quad_coordinates"] = std::make_unique<InternalField<Real>>("quad_coordinates", *this); auto && coords = *this->internals["quad_coordinates"]; coords.initialize(this->getSpatialDimension()); } /* -------------------------------------------------------------------------- */ void MaterialPython::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); auto && coords = *this->internals["quad_coordinates"]; this->model.getFEEngine().computeIntegrationPointsCoordinates( coords, &this->element_filter); auto params = local_params; params["rho"] = this->rho; try { this->callFunctor<void>("initMaterial", this->internals, params); } catch (...) { } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialPython::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto params = local_params; params["rho"] = this->rho; std::map<std::string, Array<Real> *> internal_arrays; for (auto & i : this->internals) { auto & array = (*i.second)(el_type, ghost_type); auto & name = i.first; internal_arrays[name] = &array; } this->callFunctor<void>("computeStress", this->gradu(el_type, ghost_type), this->stress(el_type, ghost_type), internal_arrays, params); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialPython::computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type) { auto params = local_params; params["rho"] = this->rho; std::map<std::string, Array<Real> *> internal_arrays; for (auto & i : this->internals) { auto & array = (*i.second)(el_type, ghost_type); auto & name = i.first; internal_arrays[name] = &array; } this->callFunctor<void>("computeTangentModuli", this->gradu(el_type, ghost_type), tangent_matrix, internal_arrays, params); } /* -------------------------------------------------------------------------- */ Real MaterialPython::getPushWaveSpeed(const Element &) const { auto params = local_params; params["rho"] = this->rho; return this->callFunctor<Real>("getPushWaveSpeed", params); } /* -------------------------------------------------------------------------- */ Real MaterialPython::getEnergyForType(const std::string & type, ElementType el_type) { AKANTU_DEBUG_IN(); std::map<std::string, Array<Real> *> internal_arrays; for (auto & i : this->internals) { auto & array = (*i.second)(el_type, _not_ghost); auto & name = i.first; internal_arrays[name] = &array; } auto params = local_params; params["rho"] = this->rho; auto & energy_density = *internal_arrays[type]; this->callFunctor<void>("getEnergyDensity", type, energy_density, this->gradu(el_type, _not_ghost), this->stress(el_type, _not_ghost), internal_arrays, params); Real energy = fem.integrate(energy_density, el_type, _not_ghost, element_filter(el_type, _not_ghost)); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real MaterialPython::getEnergy(const std::string & type) { AKANTU_DEBUG_IN(); if (this->internals.find(type) == this->internals.end()) { AKANTU_EXCEPTION("unknown energy type: " << type << " you must declare an internal named " << type); } Real energy = 0.; /// integrate the potential energy for each type of elements Mesh::type_iterator it = element_filter.firstType(spatial_dimension); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension); for (; it != last_type; ++it) { energy += this->getEnergyForType(type, *it); } AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/solid_mechanics/materials/material_python/material_python.hh b/src/model/solid_mechanics/materials/material_python/material_python.hh index e675b338b..a16c88b1e 100644 --- a/src/model/solid_mechanics/materials/material_python/material_python.hh +++ b/src/model/solid_mechanics/materials/material_python/material_python.hh @@ -1,97 +1,98 @@ /** * @file material_python.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Fri Nov 13 2015 - * @date last modification: Fri Nov 13 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Tue Feb 06 2018 * * @brief Python material * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /** * @file material_python.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * */ /* -------------------------------------------------------------------------- */ #include "python_functor.hh" /* -------------------------------------------------------------------------- */ #include "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_PYTHON_HH__ #define __AKANTU_MATERIAL_PYTHON_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class MaterialPython : public Material, PythonFunctor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialPython(SolidMechanicsModel & model, PyObject * obj, const ID & id = ""); ~MaterialPython() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void registerInternals(); void initMaterial() override; /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the tangent stiffness matrix for an element type void computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost) override; /// compute the push wave speed of the material Real getPushWaveSpeed(const Element & element) const override; /// compute an energy of the material Real getEnergy(const std::string & type) override; /// compute an energy of the material Real getEnergyForType(const std::string & type, ElementType el_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: std::map<std::string, Real> local_params; std::map<std::string, std::unique_ptr<InternalField<Real>>> internals; }; } // akantu #endif /* __AKANTU_MATERIAL_PYTHON_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_thermal.cc b/src/model/solid_mechanics/materials/material_thermal.cc index 70222c54f..22a29b48d 100644 --- a/src/model/solid_mechanics/materials/material_thermal.cc +++ b/src/model/solid_mechanics/materials/material_thermal.cc @@ -1,111 +1,110 @@ /** * @file material_thermal.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Aug 04 2015 + * @date last modification: Mon Jan 29 2018 * * @brief Specialization of the material class for the thermal material * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_thermal.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialThermal<spatial_dimension>::MaterialThermal(SolidMechanicsModel & model, const ID & id) : Material(model, id), delta_T("delta_T", *this), sigma_th("sigma_th", *this), use_previous_stress_thermal(false) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialThermal<spatial_dimension>::MaterialThermal(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Material(model, dim, mesh, fe_engine, id), delta_T("delta_T", *this, dim, fe_engine, this->element_filter), sigma_th("sigma_th", *this, dim, fe_engine, this->element_filter), use_previous_stress_thermal(false) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } template <UInt spatial_dimension> void MaterialThermal<spatial_dimension>::initialize() { this->registerParam("E", E, Real(0.), _pat_parsable | _pat_modifiable, "Young's modulus"); this->registerParam("nu", nu, Real(0.5), _pat_parsable | _pat_modifiable, "Poisson's ratio"); this->registerParam("alpha", alpha, Real(0.), _pat_parsable | _pat_modifiable, "Thermal expansion coefficient"); this->registerParam("delta_T", delta_T, _pat_parsable | _pat_modifiable, "Uniform temperature field"); delta_T.initialize(1); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialThermal<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); sigma_th.initialize(1); if (use_previous_stress_thermal) { sigma_th.initializeHistory(); } Material::initMaterial(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialThermal<dim>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); for (auto && tuple : zip(this->delta_T(el_type, ghost_type), this->sigma_th(el_type, ghost_type))) { computeStressOnQuad(std::get<1>(tuple), std::get<0>(tuple)); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL_ONLY(MaterialThermal); } // akantu diff --git a/src/model/solid_mechanics/materials/material_thermal.hh b/src/model/solid_mechanics/materials/material_thermal.hh index ee1a0fe94..d7e1d3555 100644 --- a/src/model/solid_mechanics/materials/material_thermal.hh +++ b/src/model/solid_mechanics/materials/material_thermal.hh @@ -1,108 +1,107 @@ /** * @file material_thermal.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Mon Jan 29 2018 * * @brief Material isotropic thermo-elastic * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_THERMAL_HH__ #define __AKANTU_MATERIAL_THERMAL_HH__ namespace akantu { template <UInt spatial_dimension> class MaterialThermal : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialThermal(SolidMechanicsModel & model, const ID & id = ""); MaterialThermal(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); ~MaterialThermal() override = default; protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type) override; /// local computation of thermal stress inline void computeStressOnQuad(Real & sigma, const Real & deltaT); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Young modulus Real E; /// Poisson ratio Real nu; /// Thermal expansion coefficient /// TODO : implement alpha as a matrix Real alpha; /// Temperature field InternalField<Real> delta_T; /// Current thermal stress InternalField<Real> sigma_th; /// Tell if we need to use the previous thermal stress bool use_previous_stress_thermal; }; /* ------------------------------------------------------------------------ */ /* Inline impl */ /* ------------------------------------------------------------------------ */ template <UInt dim> inline void MaterialThermal<dim>::computeStressOnQuad(Real & sigma, const Real & deltaT) { sigma = -this->E / (1. - 2. * this->nu) * this->alpha * deltaT; } template <> inline void MaterialThermal<1>::computeStressOnQuad(Real & sigma, const Real & deltaT) { sigma = -this->E * this->alpha * deltaT; } } // akantu #endif /* __AKANTU_MATERIAL_THERMAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc b/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc index f21887a1b..e103076ac 100644 --- a/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc +++ b/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc @@ -1,325 +1,324 @@ /** * @file material_standard_linear_solid_deviatoric.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Vladislav Yastrebov <vladislav.yastrebov@epfl.ch> * * @date creation: Wed May 04 2011 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Material Visco-elastic * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_standard_linear_solid_deviatoric.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialStandardLinearSolidDeviatoric<spatial_dimension>:: MaterialStandardLinearSolidDeviatoric(SolidMechanicsModel & model, const ID & id) : MaterialElastic<spatial_dimension>(model, id), stress_dev("stress_dev", *this), history_integral("history_integral", *this), dissipated_energy("dissipated_energy", *this) { AKANTU_DEBUG_IN(); this->registerParam("Eta", eta, Real(1.), _pat_parsable | _pat_modifiable, "Viscosity"); this->registerParam("Ev", Ev, Real(1.), _pat_parsable | _pat_modifiable, "Stiffness of the viscous element"); this->registerParam("Einf", E_inf, Real(1.), _pat_readable, "Stiffness of the elastic element"); UInt stress_size = spatial_dimension * spatial_dimension; this->stress_dev.initialize(stress_size); this->history_integral.initialize(stress_size); this->dissipated_energy.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); updateInternalParameters(); MaterialElastic<spatial_dimension>::initMaterial(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric< spatial_dimension>::updateInternalParameters() { MaterialElastic<spatial_dimension>::updateInternalParameters(); E_inf = this->E - this->Ev; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric<spatial_dimension>::setToSteadyState( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real> & stress_dev_vect = stress_dev(el_type, ghost_type); Array<Real> & history_int_vect = history_integral(el_type, ghost_type); Array<Real>::matrix_iterator stress_d = stress_dev_vect.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator history_int = history_int_vect.begin(spatial_dimension, spatial_dimension); /// Loop on all quadrature points MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> & dev_s = *stress_d; Matrix<Real> & h = *history_int; /// Compute the first invariant of strain Real Theta = grad_u.trace(); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) { dev_s(i, j) = 2 * this->mu * (.5 * (grad_u(i, j) + grad_u(j, i)) - 1. / 3. * Theta * (i == j)); h(i, j) = 0.; } /// Save the deviator of stress ++stress_d; ++history_int; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric<spatial_dimension>::computeStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real tau = 0.; // if(std::abs(Ev) > std::numeric_limits<Real>::epsilon()) tau = eta / Ev; Array<Real> & stress_dev_vect = stress_dev(el_type, ghost_type); Array<Real> & history_int_vect = history_integral(el_type, ghost_type); Array<Real>::matrix_iterator stress_d = stress_dev_vect.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator history_int = history_int_vect.begin(spatial_dimension, spatial_dimension); Matrix<Real> s(spatial_dimension, spatial_dimension); Real dt = this->model.getTimeStep(); Real exp_dt_tau = exp(-dt / tau); Real exp_dt_tau_2 = exp(-.5 * dt / tau); Matrix<Real> epsilon_d(spatial_dimension, spatial_dimension); Matrix<Real> epsilon_v(spatial_dimension, spatial_dimension); /// Loop on all quadrature points MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> & dev_s = *stress_d; Matrix<Real> & h = *history_int; s.clear(); sigma.clear(); /// Compute the first invariant of strain Real gamma_inf = E_inf / this->E; Real gamma_v = Ev / this->E; this->template gradUToEpsilon<spatial_dimension>(grad_u, epsilon_d); Real Theta = epsilon_d.trace(); epsilon_v.eye(Theta / Real(3.)); epsilon_d -= epsilon_v; Matrix<Real> U_rond_prim(spatial_dimension, spatial_dimension); U_rond_prim.eye(gamma_inf * this->kpa * Theta); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) { s(i, j) = 2 * this->mu * epsilon_d(i, j); h(i, j) = exp_dt_tau * h(i, j) + exp_dt_tau_2 * (s(i, j) - dev_s(i, j)); dev_s(i, j) = s(i, j); sigma(i, j) = U_rond_prim(i, j) + gamma_inf * s(i, j) + gamma_v * h(i, j); } /// Save the deviator of stress ++stress_d; ++history_int; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; this->updateDissipatedEnergy(el_type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric< spatial_dimension>::updateDissipatedEnergy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); // if(ghost_type == _ghost) return 0.; Real tau = 0.; tau = eta / Ev; Real * dis_energy = dissipated_energy(el_type, ghost_type).storage(); Array<Real> & stress_dev_vect = stress_dev(el_type, ghost_type); Array<Real> & history_int_vect = history_integral(el_type, ghost_type); Array<Real>::matrix_iterator stress_d = stress_dev_vect.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator history_int = history_int_vect.begin(spatial_dimension, spatial_dimension); Matrix<Real> q(spatial_dimension, spatial_dimension); Matrix<Real> q_rate(spatial_dimension, spatial_dimension); Matrix<Real> epsilon_d(spatial_dimension, spatial_dimension); Matrix<Real> epsilon_v(spatial_dimension, spatial_dimension); Real dt = this->model.getTimeStep(); Real gamma_v = Ev / this->E; Real alpha = 1. / (2. * this->mu * gamma_v); /// Loop on all quadrature points MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> & dev_s = *stress_d; Matrix<Real> & h = *history_int; /// Compute the first invariant of strain this->template gradUToEpsilon<spatial_dimension>(grad_u, epsilon_d); Real Theta = epsilon_d.trace(); epsilon_v.eye(Theta / Real(3.)); epsilon_d -= epsilon_v; q.copy(dev_s); q -= h; q *= gamma_v; q_rate.copy(dev_s); q_rate *= gamma_v; q_rate -= q; q_rate /= tau; for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) *dis_energy += (epsilon_d(i, j) - alpha * q(i, j)) * q_rate(i, j) * dt; /// Save the deviator of stress ++stress_d; ++history_int; ++dis_energy; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric< spatial_dimension>::getDissipatedEnergy() const { AKANTU_DEBUG_IN(); Real de = 0.; /// integrate the dissipated energy for each type of elements for (auto & type : this->element_filter.elementTypes(spatial_dimension, _not_ghost)) { de += this->fem.integrate(dissipated_energy(type, _not_ghost), type, _not_ghost, this->element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return de; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric< spatial_dimension>::getDissipatedEnergy(ElementType type, UInt index) const { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = this->fem.getNbIntegrationPoints(type); auto it = this->dissipated_energy(type, _not_ghost).begin(nb_quadrature_points); UInt gindex = (this->element_filter(type, _not_ghost))(index); AKANTU_DEBUG_OUT(); return this->fem.integrate(it[index], type, gindex); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric<spatial_dimension>::getEnergy( const std::string & type) { if (type == "dissipated") return getDissipatedEnergy(); else if (type == "dissipated_sls_deviatoric") return getDissipatedEnergy(); else return MaterialElastic<spatial_dimension>::getEnergy(type); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric<spatial_dimension>::getEnergy( const std::string & energy_id, ElementType type, UInt index) { if (energy_id == "dissipated") return getDissipatedEnergy(type, index); else if (energy_id == "dissipated_sls_deviatoric") return getDissipatedEnergy(type, index); else return MaterialElastic<spatial_dimension>::getEnergy(energy_id, type, index); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(sls_deviatoric, MaterialStandardLinearSolidDeviatoric); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh b/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh index a5a70a7ff..6b39c6d49 100644 --- a/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh +++ b/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh @@ -1,136 +1,135 @@ /** * @file material_standard_linear_solid_deviatoric.hh * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Vladislav Yastrebov <vladislav.yastrebov@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 08 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Material Visco-elastic, based on Standard Solid rheological model, * see * [] J.C. Simo, T.J.R. Hughes, "Computational Inelasticity", Springer (1998), * see Sections 10.2 and 10.3 * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_elastic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_STANDARD_LINEAR_SOLID_DEVIATORIC_HH__ #define __AKANTU_MATERIAL_STANDARD_LINEAR_SOLID_DEVIATORIC_HH__ namespace akantu { /** * Material standard linear solid deviatoric * * * @verbatim E_\inf ------|\/\/\|------ | | ---| |--- | | ----|\/\/\|--[|---- E_v \eta @endverbatim * * keyword : sls_deviatoric * * parameters in the material files : * - E : Initial Young's modulus @f$ E = E_i + E_v @f$ * - eta : viscosity * - Ev : stiffness of the viscous element */ template <UInt spatial_dimension> class MaterialStandardLinearSolidDeviatoric : public MaterialElastic<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialStandardLinearSolidDeviatoric(SolidMechanicsModel & model, const ID & id = ""); ~MaterialStandardLinearSolidDeviatoric() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter void initMaterial() override; /// update the internal parameters (for modifiable parameters) void updateInternalParameters() override; /// set material to steady state void setToSteadyState(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; protected: /// update the dissipated energy, is called after the stress have been /// computed void updateDissipatedEnergy(ElementType el_type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// give the dissipated energy for the time step Real getDissipatedEnergy() const; Real getDissipatedEnergy(ElementType type, UInt index) const; /// get the energy using an energy type string for the time step Real getEnergy(const std::string & type) override; Real getEnergy(const std::string & energy_id, ElementType type, UInt index) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// viscosity, viscous elastic modulus Real eta, Ev, E_inf; /// history of deviatoric stress InternalField<Real> stress_dev; /// Internal variable: history integral InternalField<Real> history_integral; /// Dissipated energy InternalField<Real> dissipated_energy; }; } // namespace akantu #endif /* __AKANTU_MATERIAL_STANDARD_LINEAR_SOLID_DEVIATORIC_HH__ */ diff --git a/src/model/solid_mechanics/materials/plane_stress_toolbox.hh b/src/model/solid_mechanics/materials/plane_stress_toolbox.hh index 1387b8f97..00c017adc 100644 --- a/src/model/solid_mechanics/materials/plane_stress_toolbox.hh +++ b/src/model/solid_mechanics/materials/plane_stress_toolbox.hh @@ -1,102 +1,103 @@ /** * @file plane_stress_toolbox.hh * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 16 2014 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Tools to implement the plane stress behavior in a material * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PLANE_STRESS_TOOLBOX_HH__ #define __AKANTU_PLANE_STRESS_TOOLBOX_HH__ namespace akantu { class SolidMechanicsModel; class FEEngine; } // akantu namespace akantu { /** * Empty class in dimensions different from 2 * This class is only specialized for 2D in the tmpl file */ template <UInt dim, class ParentMaterial = Material> class PlaneStressToolbox : public ParentMaterial { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PlaneStressToolbox(SolidMechanicsModel & model, const ID & id = "") : ParentMaterial(model, id) {} PlaneStressToolbox(SolidMechanicsModel & model, UInt spatial_dimension, const Mesh & mesh, FEEngine & fe_engine, const ID & id = "") : ParentMaterial(model, spatial_dimension, mesh, fe_engine, id) {} ~PlaneStressToolbox() override = default; protected: void initialize(); public: void computeAllCauchyStresses(GhostType ghost_type = _not_ghost) override { ParentMaterial::computeAllCauchyStresses(ghost_type); } virtual void computeCauchyStressPlaneStress(ElementType /*el_type*/, GhostType /*ghost_type*/) { AKANTU_DEBUG_IN(); AKANTU_ERROR("The function \"computeCauchyStressPlaneStress\" can " "only be used in 2D Plane stress problems, which means " "that you made a mistake somewhere!! "); AKANTU_DEBUG_OUT(); } virtual void computeThirdAxisDeformation(ElementType, GhostType) {} protected: bool initialize_third_axis_deformation{false}; }; #define AKANTU_PLANE_STRESS_TOOL_SPEC(dim) \ template <> \ inline PlaneStressToolbox<dim, Material>::PlaneStressToolbox( \ SolidMechanicsModel & model, const ID & id) \ : Material(model, id) {} AKANTU_PLANE_STRESS_TOOL_SPEC(1) AKANTU_PLANE_STRESS_TOOL_SPEC(3) } // namespace akantu #include "plane_stress_toolbox_tmpl.hh" #endif /* __AKANTU_PLANE_STRESS_TOOLBOX_HH__ */ diff --git a/src/model/solid_mechanics/materials/plane_stress_toolbox_tmpl.hh b/src/model/solid_mechanics/materials/plane_stress_toolbox_tmpl.hh index 9ef31be49..5cfdcdf1e 100644 --- a/src/model/solid_mechanics/materials/plane_stress_toolbox_tmpl.hh +++ b/src/model/solid_mechanics/materials/plane_stress_toolbox_tmpl.hh @@ -1,169 +1,169 @@ /** * @file plane_stress_toolbox_tmpl.hh * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * * @date creation: Tue Sep 16 2014 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Wed Nov 08 2017 * * @brief 2D specialization of the akantu::PlaneStressToolbox class * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PLANE_STRESS_TOOLBOX_TMPL_HH__ #define __AKANTU_PLANE_STRESS_TOOLBOX_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class ParentMaterial> class PlaneStressToolbox<2, ParentMaterial> : public ParentMaterial { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PlaneStressToolbox(SolidMechanicsModel & model, const ID & id = ""); PlaneStressToolbox(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); ~PlaneStressToolbox() override = default; AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ThirdAxisDeformation, third_axis_deformation, Real); protected: void initialize() { this->registerParam("Plane_Stress", plane_stress, false, _pat_parsmod, "Is plane stress"); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ void initMaterial() override { ParentMaterial::initMaterial(); if (this->plane_stress && this->initialize_third_axis_deformation) { this->third_axis_deformation.initialize(1); this->third_axis_deformation.resize(); } } /* ------------------------------------------------------------------------ */ void computeStress(ElementType el_type, GhostType ghost_type) override { ParentMaterial::computeStress(el_type, ghost_type); if (this->plane_stress) computeThirdAxisDeformation(el_type, ghost_type); } /* ------------------------------------------------------------------------ */ virtual void computeThirdAxisDeformation(ElementType, GhostType) {} /// Computation of Cauchy stress tensor in the case of finite deformation void computeAllCauchyStresses(GhostType ghost_type = _not_ghost) override { AKANTU_DEBUG_IN(); if (this->plane_stress) { AKANTU_DEBUG_ASSERT(this->finite_deformation, "The Cauchy stress can only be computed if you are " "working in finite deformation."); // resizeInternalArray(stress); Mesh::type_iterator it = this->fem.getMesh().firstType(2, ghost_type); Mesh::type_iterator last_type = this->fem.getMesh().lastType(2, ghost_type); for (; it != last_type; ++it) this->computeCauchyStressPlaneStress(*it, ghost_type); } else ParentMaterial::computeAllCauchyStresses(ghost_type); AKANTU_DEBUG_OUT(); } virtual void computeCauchyStressPlaneStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost){}; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// third axis strain measure value InternalField<Real> third_axis_deformation; /// Plane stress or plane strain bool plane_stress; /// For non linear materials, the \epsilon_{zz} might be required bool initialize_third_axis_deformation; }; template <class ParentMaterial> inline PlaneStressToolbox<2, ParentMaterial>::PlaneStressToolbox( SolidMechanicsModel & model, const ID & id) : ParentMaterial(model, id), third_axis_deformation("third_axis_deformation", *this), plane_stress(false), initialize_third_axis_deformation(false) { /// @todo Plane_Stress should not be possible to be modified after /// initMaterial (but before) this->initialize(); } template <class ParentMaterial> inline PlaneStressToolbox<2, ParentMaterial>::PlaneStressToolbox( SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : ParentMaterial(model, dim, mesh, fe_engine, id), third_axis_deformation("third_axis_deformation", *this, dim, fe_engine, this->element_filter), plane_stress(false), initialize_third_axis_deformation(false) { this->initialize(); } template <> inline PlaneStressToolbox<2, Material>::PlaneStressToolbox( SolidMechanicsModel & model, const ID & id) : Material(model, id), third_axis_deformation("third_axis_deformation", *this), plane_stress(false), initialize_third_axis_deformation(false) { /// @todo Plane_Stress should not be possible to be modified after /// initMaterial (but before) this->registerParam("Plane_Stress", plane_stress, false, _pat_parsmod, "Is plane stress"); } } // namespace akantu #endif /* __AKANTU_PLANE_STRESS_TOOLBOX_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/materials/random_internal_field.hh b/src/model/solid_mechanics/materials/random_internal_field.hh index ebb9c03c6..a6511b6c9 100644 --- a/src/model/solid_mechanics/materials/random_internal_field.hh +++ b/src/model/solid_mechanics/materials/random_internal_field.hh @@ -1,105 +1,104 @@ /** * @file random_internal_field.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Random internal material parameter * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_random_generator.hh" #include "internal_field.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_RANDOM_INTERNAL_FIELD_HH__ #define __AKANTU_RANDOM_INTERNAL_FIELD_HH__ namespace akantu { /** * class for the internal fields of materials with a random * distribution */ template <typename T, template <typename> class BaseField = InternalField, template <typename> class Generator = RandomGenerator> class RandomInternalField : public BaseField<T> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: RandomInternalField(const ID & id, Material & material); ~RandomInternalField() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ RandomInternalField operator=(const RandomInternalField &) = delete; public: AKANTU_GET_MACRO(RandomParameter, random_parameter, const RandomParameter<T>); /// initialize the field to a given number of component void initialize(UInt nb_component) override; /// set the field to a given value void setDefaultValue(const T & value) override; /// set the specified random distribution to a given parameter void setRandomDistribution(const RandomParameter<T> & param); /// print the content void printself(std::ostream & stream, int indent = 0) const override; protected: void setArrayValues(T * begin, T * end) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: inline operator Real() const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// random parameter containing the distribution and base value RandomParameter<T> random_parameter; }; /// standard output stream operator template <typename T> inline std::ostream & operator<<(std::ostream & stream, const RandomInternalField<T> & _this) { _this.printself(stream); return stream; } } // akantu #endif /* __AKANTU_RANDOM_INTERNAL_FIELD_HH__ */ diff --git a/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh b/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh index ed64c4371..4f2769960 100644 --- a/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh +++ b/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh @@ -1,125 +1,125 @@ /** * @file random_internal_field_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Thu Feb 08 2018 * * @brief Random internal material parameter implementation * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_random_generator.hh" #include "internal_field_tmpl.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_RANDOM_INTERNAL_FIELD_TMPL_HH__ #define __AKANTU_RANDOM_INTERNAL_FIELD_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T, template <typename> class BaseField, template <typename> class Generator> RandomInternalField<T, BaseField, Generator>::RandomInternalField( const ID & id, Material & material) : BaseField<T>(id, material), random_parameter(T()) {} /* -------------------------------------------------------------------------- */ template <typename T, template <typename> class BaseField, template <typename> class Generator> RandomInternalField<T, BaseField, Generator>::~RandomInternalField() = default; /* -------------------------------------------------------------------------- */ template <typename T, template <typename> class BaseField, template <typename> class Generator> void RandomInternalField<T, BaseField, Generator>::initialize( UInt nb_component) { this->internalInitialize(nb_component); } /* ------------------------------------------------------------------------ */ template <typename T, template <typename> class BaseField, template <typename> class Generator> void RandomInternalField<T, BaseField, Generator>::setDefaultValue( const T & value) { random_parameter.setBaseValue(value); this->reset(); } /* ------------------------------------------------------------------------ */ template <typename T, template <typename> class BaseField, template <typename> class Generator> void RandomInternalField<T, BaseField, Generator>::setRandomDistribution( const RandomParameter<T> & param) { random_parameter = param; this->reset(); } /* ------------------------------------------------------------------------ */ template <typename T, template <typename> class BaseField, template <typename> class Generator> void RandomInternalField<T, BaseField, Generator>::printself( std::ostream & stream, int indent[[gnu::unused]]) const { stream << "RandomInternalField [ "; random_parameter.printself(stream); stream << " ]"; #if !defined(AKANTU_NDEBUG) if (AKANTU_DEBUG_TEST(dblDump)) { stream << std::endl; InternalField<T>::printself(stream, indent); } #endif } /* -------------------------------------------------------------------------- */ template <typename T, template <typename> class BaseField, template <typename> class Generator> void RandomInternalField<T, BaseField, Generator>::setArrayValues(T * begin, T * end) { random_parameter.template setValues<Generator>(begin, end); } /* -------------------------------------------------------------------------- */ template <typename T, template <typename> class BaseField, template <typename> class Generator> inline RandomInternalField<T, BaseField, Generator>::operator Real() const { return random_parameter.getBaseValue(); } /* -------------------------------------------------------------------------- */ template <> inline void ParameterTyped<RandomInternalField<Real>>::setAuto( const ParserParameter & in_param) { Parameter::setAuto(in_param); RandomParameter<Real> r = in_param; param.setRandomDistribution(r); } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_RANDOM_INTERNAL_FIELD_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function.hh index 7ffbfdbf3..95d494d05 100644 --- a/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function.hh +++ b/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function.hh @@ -1,82 +1,82 @@ /** * @file damaged_weight_function.hh * + * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Damaged weight function for non local materials * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "base_weight_function.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DAMAGED_WEIGHT_FUNCTION_HH__ #define __AKANTU_DAMAGED_WEIGHT_FUNCTION_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Damage weight function */ /* -------------------------------------------------------------------------- */ class DamagedWeightFunction : public BaseWeightFunction { public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ DamagedWeightFunction(NonLocalManager & manager) : BaseWeightFunction(manager, "damaged"), damage(nullptr) { this->init(); } /* -------------------------------------------------------------------------- */ /* Base Weight Function inherited methods */ /* -------------------------------------------------------------------------- */ /// set the pointers of internals to the right flattend version void init() override; inline Real operator()(Real r, const __attribute__((unused)) IntegrationPoint & q1, const IntegrationPoint & q2); private: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ /// internal pointer to the current damage vector ElementTypeMapReal * damage; }; #if defined(AKANTU_INCLUDE_INLINE_IMPL) #include "damaged_weight_function_inline_impl.cc" #endif } // namespace akantu #endif /* __AKANTU_DAMAGED_WEIGHT_FUNCTION_HH__ */ diff --git a/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function_inline_impl.cc b/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function_inline_impl.cc index 8752fe003..c6595d2a9 100644 --- a/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function_inline_impl.cc +++ b/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function_inline_impl.cc @@ -1,75 +1,75 @@ /** * @file damaged_weight_function_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Mon Aug 24 2015 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Feb 03 2016 * * @brief Implementation of inline function of damaged weight function * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline Real DamagedWeightFunction::operator()(Real r, const __attribute__((unused)) IntegrationPoint & q1, const IntegrationPoint & q2) { /// compute the weight UInt quad = q2.global_num; Array<Real> & dam_array = (*this->damage)(q2.type, q2.ghost_type); Real D = dam_array(quad); Real Radius_t = 0; Real Radius_init = this->R2; // if(D <= 0.5) // { // Radius_t = 2*D*Radius_init; // } // else // { // Radius_t = 2*Radius_init*(1-D); // } // Radius_t = Radius_init * (1 - D); Radius_init *= Radius_init; Radius_t *= Radius_t; if (Radius_t < Math::getTolerance()) { Radius_t = 0.001 * Radius_init; } Real expb = (2 * std::log(0.51)) / (std::log(1.0 - 0.49 * Radius_t / Radius_init)); Int expb_floor = std::floor(expb); Real b = expb_floor + expb_floor % 2; Real alpha = std::max(0., 1. - r * r / Radius_init); Real w = std::pow(alpha, b); return w; } /* -------------------------------------------------------------------------- */ inline void DamagedWeightFunction::init() { this->damage = &(this->manager.registerWeightFunctionInternal("damage")); } diff --git a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function.hh index 3a5ca0524..b79e308bf 100644 --- a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function.hh +++ b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function.hh @@ -1,96 +1,96 @@ /** * @file remove_damaged_weight_function.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Mon Aug 24 2015 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Removed damaged weight function for non local materials * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "base_weight_function.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_REMOVE_DAMAGED_WEIGHT_FUNCTION_HH__ #define __AKANTU_REMOVE_DAMAGED_WEIGHT_FUNCTION_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Remove damaged weight function */ /* -------------------------------------------------------------------------- */ class RemoveDamagedWeightFunction : public BaseWeightFunction { public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ RemoveDamagedWeightFunction(NonLocalManager & manager) : BaseWeightFunction(manager, "remove_damaged"), damage(nullptr) { this->registerParam("damage_limit", this->damage_limit, 1., _pat_parsable, "Damage Threshold"); this->init(); } /* -------------------------------------------------------------------------- */ /* Base Weight Function inherited methods */ /* -------------------------------------------------------------------------- */ inline void init() override; inline Real operator()(Real r, const IntegrationPoint & q1, const IntegrationPoint & q2); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; private: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ /// limit at which a point is considered as complitely broken Real damage_limit; /// internal pointer to the current damage vector ElementTypeMapReal * damage; }; } // namespace akantu #include "remove_damaged_weight_function_inline_impl.cc" #endif /* __AKANTU_REMOVE_DAMAGED_WEIGHT_FUNCTION_HH__ */ diff --git a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function_inline_impl.cc b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function_inline_impl.cc index 326454778..ea10a3db2 100644 --- a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function_inline_impl.cc +++ b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function_inline_impl.cc @@ -1,103 +1,104 @@ /** * @file remove_damaged_weight_function_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Mon Aug 24 2015 - * @date last modification: Wed Oct 21 2015 + * @date last modification: Thu Jul 06 2017 * * @brief Implementation of inline function of remove damaged weight function * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "remove_damaged_weight_function.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_REMOVE_DAMAGED_WEIGHT_FUNCTION_INLINE_IMPL_CC__ #define __AKANTU_REMOVE_DAMAGED_WEIGHT_FUNCTION_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline Real RemoveDamagedWeightFunction:: operator()(Real r, const __attribute__((unused)) IntegrationPoint & q1, const IntegrationPoint & q2) { /// compute the weight UInt quad = q2.global_num; if (q1 == q2) return 1.; Array<Real> & dam_array = (*this->damage)(q2.type, q2.ghost_type); Real D = dam_array(quad); Real w = 0.; if (D < damage_limit * (1 - Math::getTolerance())) { Real alpha = std::max(0., 1. - r * r / this->R2); w = alpha * alpha; } return w; } /* -------------------------------------------------------------------------- */ inline void RemoveDamagedWeightFunction::init() { this->damage = &(this->manager.registerWeightFunctionInternal("damage")); } /* -------------------------------------------------------------------------- */ inline UInt RemoveDamagedWeightFunction::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_mnl_weight) return this->manager.getModel().getNbIntegrationPoints(elements) * sizeof(Real); return 0; } /* -------------------------------------------------------------------------- */ inline void RemoveDamagedWeightFunction::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_mnl_weight) { DataAccessor<Element>::packElementalDataHelper<Real>( *damage, buffer, elements, true, this->manager.getModel().getFEEngine()); } } /* -------------------------------------------------------------------------- */ inline void RemoveDamagedWeightFunction::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_mnl_weight) { DataAccessor<Element>::unpackElementalDataHelper<Real>( *damage, buffer, elements, true, this->manager.getModel().getFEEngine()); } } } // namespace akantu #endif /* __AKANTU_REMOVE_DAMAGED_WEIGHT_FUNCTION_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function.hh index e4664c861..fc956fa1a 100644 --- a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function.hh +++ b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function.hh @@ -1,86 +1,85 @@ /** * @file remove_damaged_with_damage_rate_weight_function.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Removed damaged weight function for non local materials * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "base_weight_function.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_REMOVE_DAMAGED_WITH_DAMAGE_RATE_WEIGHT_FUNCTION_HH__ #define __AKANTU_REMOVE_DAMAGED_WITH_DAMAGE_RATE_WEIGHT_FUNCTION_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Remove damaged with damage rate weight function */ /* -------------------------------------------------------------------------- */ class RemoveDamagedWithDamageRateWeightFunction : public BaseWeightFunction { public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ RemoveDamagedWithDamageRateWeightFunction(NonLocalManager & manager) : BaseWeightFunction(manager, "remove_damage_with_damage_rate"), damage_with_damage_rate(nullptr) { this->registerParam<Real>("damage_limit", this->damage_limit_with_damage_rate, 1, _pat_parsable, "Damage Threshold"); this->init(); } /* -------------------------------------------------------------------------- */ /* Base Weight Function inherited methods */ /* -------------------------------------------------------------------------- */ inline Real operator()(Real r, const __attribute__((unused)) IntegrationPoint & q1, const IntegrationPoint & q2); inline void init() override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// limit at which a point is considered as complitely broken Real damage_limit_with_damage_rate; /// internal pointer to the current damage vector ElementTypeMapReal * damage_with_damage_rate; }; #if defined(AKANTU_INCLUDE_INLINE_IMPL) #include "remove_damaged_with_damage_rate_weight_function_inline_impl.cc" #endif } // akantu #endif /* __AKANTU_REMOVE_DAMAGED_WITH_DAMAGE_WEIGHT_FUNCTION_HH__ */ diff --git a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function_inline_impl.cc b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function_inline_impl.cc index 2c9b3d939..f36ed8b8b 100644 --- a/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function_inline_impl.cc +++ b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function_inline_impl.cc @@ -1,62 +1,62 @@ /** * @file remove_damaged_with_damage_rate_weight_function_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Mon Aug 24 2015 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Feb 03 2016 * * @brief Implementation of inline function of remove damaged with * damage rate weight function * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline void RemoveDamagedWithDamageRateWeightFunction::init() { this->damage_with_damage_rate = &(this->manager.registerWeightFunctionInternal("damage-rate")); } /* -------------------------------------------------------------------------- */ inline Real RemoveDamagedWithDamageRateWeightFunction:: operator()(Real r, const __attribute__((unused)) IntegrationPoint & q1, const IntegrationPoint & q2) { /// compute the weight UInt quad = q2.global_num; if (q1.global_num == quad) return 1.; Array<Real> & dam_array = (*this->damage_with_damage_rate)(q2.type, q2.ghost_type); Real D = dam_array(quad); Real w = 0.; Real alphaexp = 1.; Real betaexp = 2.; if (D < damage_limit_with_damage_rate) { Real alpha = std::max(0., 1. - pow((r * r / this->R2), alphaexp)); w = pow(alpha, betaexp); } return w; } diff --git a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc index 992297710..e3913c320 100644 --- a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc +++ b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc @@ -1,123 +1,123 @@ /** * @file stress_based_weight_function.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Aug 24 2015 - * @date last modification: Wed Oct 07 2015 + * @date last modification: Tue Feb 20 2018 * * @brief implementation of the stres based weight function classes * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "stress_based_weight_function.hh" namespace akantu { /* -------------------------------------------------------------------------- */ StressBasedWeightFunction::StressBasedWeightFunction(NonLocalManager & manager) : BaseWeightFunction(manager, "stress_based") // stress_diag("stress_diag", material), selected_stress_diag(NULL), // stress_base("stress_base", material), selected_stress_base(NULL), // characteristic_size("lc", material), selected_characteristic_size(NULL) { // this->registerParam("ft", this->ft, 0., _pat_parsable, "Tensile strength"); // stress_diag.initialize(spatial_dimension); // stress_base.initialize(spatial_dimension * spatial_dimension); // characteristic_size.initialize(1); } /* -------------------------------------------------------------------------- */ /// During intialization the characteristic sizes for all quadrature /// points are computed void StressBasedWeightFunction::init() { // const Mesh & mesh = this->material.getModel().getFEEngine().getMesh(); // for (UInt g = _not_ghost; g <= _ghost; ++g) { // GhostType gt = GhostType(g); // Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt); // Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, gt); // for(; it != last_type; ++it) { // UInt nb_quadrature_points = // this->material.getModel().getFEEngine().getNbQuadraturePoints(*it, gt); // const Array<UInt> & element_filter = // this->material.getElementFilter(*it, gt); // UInt nb_element = element_filter.size(); // Array<Real> ones(nb_element*nb_quadrature_points, 1, 1.); // Array<Real> & lc = characteristic_size(*it, gt); // this->material.getModel().getFEEngine().integrateOnQuadraturePoints(ones, // lc, // 1, // *it, // gt, // element_filter); // for (UInt q = 0; q < nb_quadrature_points * nb_element; q++) { // lc(q) = pow(lc(q), 1./ Real(spatial_dimension)); // } // } // } } /* -------------------------------------------------------------------------- */ /// computation of principals stresses and principal directions void StressBasedWeightFunction::updatePrincipalStress(__attribute__((unused)) GhostType ghost_type) { // AKANTU_DEBUG_IN(); // const Mesh & mesh = this->material.getModel().getFEEngine().getMesh(); // Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); // Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, // ghost_type); // for(; it != last_type; ++it) { // Array<Real>::const_matrix_iterator sigma = // this->material.getStress(*it, ghost_type).begin(spatial_dimension, // spatial_dimension); // auto eigenvalues = // stress_diag(*it, ghost_type).begin(spatial_dimension); // auto eigenvalues_end = // stress_diag(*it, ghost_type).end(spatial_dimension); // Array<Real>::matrix_iterator eigenvector = // stress_base(*it, ghost_type).begin(spatial_dimension, // spatial_dimension); // #ifndef __trick__ // auto cl = characteristic_size(*it, ghost_type).begin(); // #endif // UInt q = 0; // for(;eigenvalues != eigenvalues_end; ++sigma, ++eigenvalues, // ++eigenvector, ++cl, ++q) { // sigma->eig(*eigenvalues, *eigenvector); // *eigenvalues /= ft; // #ifndef __trick__ // // specify a lower bound for principal stress based on the size of // the element // for (UInt i = 0; i < spatial_dimension; ++i) { // (*eigenvalues)(i) = std::max(*cl / this->R, (*eigenvalues)(i)); // } // #endif // } // } // AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.hh index a2e1debd7..60897da5c 100644 --- a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.hh +++ b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.hh @@ -1,101 +1,101 @@ /** * @file stress_based_weight_function.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Mon Aug 24 2015 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Removed damaged weight function for non local materials * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "base_weight_function.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRESS_BASED_WEIGHT_FUNCTION_HH__ #define __AKANTU_STRESS_BASED_WEIGHT_FUNCTION_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Stress Based Weight */ /* -------------------------------------------------------------------------- */ /// based on based on Giry et al.: Stress-based nonlocal damage model, /// IJSS, 48, 2011 class StressBasedWeightFunction : public BaseWeightFunction { public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ StressBasedWeightFunction(NonLocalManager & manager); /* -------------------------------------------------------------------------- */ /* Base Weight Function inherited methods */ /* -------------------------------------------------------------------------- */ void init() override; inline void updateInternals() override; void updatePrincipalStress(GhostType ghost_type); inline void updateQuadraturePointsCoordinates( ElementTypeMapArray<Real> & quadrature_points_coordinates); inline Real operator()(Real r, const IntegrationPoint & q1, const IntegrationPoint & q2); /// computation of ellipsoid inline Real computeRhoSquare(Real r, Vector<Real> & eigs, Matrix<Real> & eigenvects, Vector<Real> & x_s); protected: inline void setInternal(); private: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ /// tensile strength Real ft; /// prinicipal stresses ElementTypeMapReal * stress_diag; /// for preselection of types (optimization) ElementTypeMapReal * selected_stress_diag; /// principal directions ElementTypeMapReal * stress_base; /// lenght intrinisic to the material ElementTypeMapReal * characteristic_size; }; #if defined(AKANTU_INCLUDE_INLINE_IMPL) #include "stress_based_weight_function_inline_impl.cc" #endif } // akantu #endif /* __AKANTU_STRESS_BASED_WEIGHT_FUNCTION_HH__ */ diff --git a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function_inline_impl.cc b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function_inline_impl.cc index 2990dd1d4..3ac8d4cb9 100644 --- a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function_inline_impl.cc +++ b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function_inline_impl.cc @@ -1,191 +1,190 @@ /** * @file stress_based_weight_function_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Fri Apr 13 2012 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Feb 03 2016 * * @brief Implementation of inline function of remove damaged with * damage rate weight function * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline void StressBasedWeightFunction::updateInternals() { // updatePrincipalStress(_not_ghost); // updatePrincipalStress(_ghost); } /* -------------------------------------------------------------------------- */ // inline void StressBasedWeightFunction::selectType(ElementType type1, // GhostType ghost_type1, // ElementType type2, // GhostType ghost_type2) { // selected_stress_diag = &stress_diag(type2, ghost_type2); // selected_stress_base = &stress_base(type2, ghost_type2); // selected_characteristic_size = &characteristic_size(type1, ghost_type1); // } /* -------------------------------------------------------------------------- */ inline Real StressBasedWeightFunction::computeRhoSquare( __attribute__((unused)) Real r, __attribute__((unused)) Vector<Real> & eigs, __attribute__((unused)) Matrix<Real> & eigenvects, __attribute__((unused)) Vector<Real> & x_s) { // if (spatial_dimension == 1) // return eigs[0]; // else if (spatial_dimension == 2) { // Vector<Real> u1(eigenvects.storage(), 2); // Real cos_t = x_s.dot(u1) / (x_s.norm() * u1.norm()); // Real cos_t_2; // Real sin_t_2; // Real sigma1_2 = eigs[0]*eigs[0]; // Real sigma2_2 = eigs[1]*eigs[1]; // #ifdef __trick__ // Real zero = std::numeric_limits<Real>::epsilon(); // if(std::abs(cos_t) < zero) { // cos_t_2 = 0; // sin_t_2 = 1; // } else { // cos_t_2 = cos_t * cos_t; // sin_t_2 = (1 - cos_t_2); // } // Real rhop1 = std::max(0., cos_t_2 / sigma1_2); // Real rhop2 = std::max(0., sin_t_2 / sigma2_2); // #else // cos_t_2 = cos_t * cos_t; // sin_t_2 = (1 - cos_t_2); // Real rhop1 = cos_t_2 / sigma1_2; // Real rhop2 = sin_t_2 / sigma2_2; // #endif // return 1./ (rhop1 + rhop2); // } else if (spatial_dimension == 3) { // Vector<Real> u1(eigenvects.storage() + 0*3, 3); // //Vector<Real> u2(eigenvects.storage() + 1*3, 3); // Vector<Real> u3(eigenvects.storage() + 2*3, 3); // Real zero = std::numeric_limits<Real>::epsilon(); // Vector<Real> tmp(3); // tmp.crossProduct(x_s, u3); // Vector<Real> u3_C_x_s_C_u3(3); // u3_C_x_s_C_u3.crossProduct(u3, tmp); // Real norm_u3_C_x_s_C_u3 = u3_C_x_s_C_u3.norm(); // Real cos_t = 0.; // if(std::abs(norm_u3_C_x_s_C_u3) > zero) { // Real inv_norm_u3_C_x_s_C_u3 = 1. / norm_u3_C_x_s_C_u3; // cos_t = u1.dot(u3_C_x_s_C_u3) * inv_norm_u3_C_x_s_C_u3; // } // Real cos_p = u3.dot(x_s) / r; // Real cos_t_2; // Real sin_t_2; // Real cos_p_2; // Real sin_p_2; // Real sigma1_2 = eigs[0]*eigs[0]; // Real sigma2_2 = eigs[1]*eigs[1]; // Real sigma3_2 = eigs[2]*eigs[2]; // #ifdef __trick__ // if(std::abs(cos_t) < zero) { // cos_t_2 = 0; // sin_t_2 = 1; // } else { // cos_t_2 = cos_t * cos_t; // sin_t_2 = (1 - cos_t_2); // } // if(std::abs(cos_p) < zero) { // cos_p_2 = 0; // sin_p_2 = 1; // } else { // cos_p_2 = cos_p * cos_p; // sin_p_2 = (1 - cos_p_2); // } // Real rhop1 = std::max(0., sin_p_2 * cos_t_2 / sigma1_2); // Real rhop2 = std::max(0., sin_p_2 * sin_t_2 / sigma2_2); // Real rhop3 = std::max(0., cos_p_2 / sigma3_2); // #else // cos_t_2 = cos_t * cos_t; // sin_t_2 = (1 - cos_t_2); // cos_p_2 = cos_p * cos_p; // sin_p_2 = (1 - cos_p_2); // Real rhop1 = sin_p_2 * cos_t_2 / sigma1_2; // Real rhop2 = sin_p_2 * sin_t_2 / sigma2_2; // Real rhop3 = cos_p_2 / sigma3_2; // #endif // return 1./ (rhop1 + rhop2 + rhop3); // } return 0.; } /* -------------------------------------------------------------------------- */ inline Real StressBasedWeightFunction:: operator()(__attribute__((unused)) Real r, __attribute__((unused)) const IntegrationPoint & q1, __attribute__((unused)) const IntegrationPoint & q2) { // Real zero = std::numeric_limits<Real>::epsilon(); // if(r < zero) return 1.; // means x and s are the same points // const Vector<Real> & x = q1.getPosition(); // const Vector<Real> & s = q2.getPosition(); // Vector<Real> eigs = // selected_stress_diag->begin(spatial_dimension)[q2.global_num]; // Matrix<Real> eigenvects = // selected_stress_base->begin(spatial_dimension, // spatial_dimension)[q2.global_num]; // Real min_rho_lc = selected_characteristic_size->begin()[q1.global_num]; // Vector<Real> x_s(spatial_dimension); // x_s = x; // x_s -= s; // Real rho_2 = computeRhoSquare(r, eigs, eigenvects, x_s); // Real rho_lc_2 = std::max(this->R2 * rho_2, min_rho_lc*min_rho_lc); // // Real w = std::max(0., 1. - r*r / rho_lc_2); // // w = w*w; // Real w = exp(- 2*2*r*r / rho_lc_2); // return w; return 0.; } diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index ba8c9bcd2..61b9662de 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1212 +1,1211 @@ /** * @file solid_mechanics_model.cc * * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jul 27 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of the SolidMechanicsModel 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "solid_mechanics_model_tmpl.hh" #include "communicator.hh" #include "element_synchronizer.hh" #include "sparse_matrix.hh" #include "synchronizer_registry.hh" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif #include "material_non_local.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id, const ModelType model_type) : Model(mesh, model_type, dim, id, memory_id), BoundaryCondition<SolidMechanicsModel>(), f_m2a(1.0), displacement(nullptr), previous_displacement(nullptr), displacement_increment(nullptr), mass(nullptr), velocity(nullptr), acceleration(nullptr), external_force(nullptr), internal_force(nullptr), blocked_dofs(nullptr), current_position(nullptr), material_index("material index", id, memory_id), material_local_numbering("material local numbering", id, memory_id), increment_flag(false), are_materials_instantiated(false) { AKANTU_DEBUG_IN(); this->registerFEEngineObject<MyFEEngineType>("SolidMechanicsFEEngine", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); this->mesh.addDumpMesh(mesh, Model::spatial_dimension, _not_ghost, _ek_regular); #endif material_selector = std::make_shared<DefaultMaterialSelector>(material_index), this->initDOFManager(); this->registerDataAccessor(*this); if (this->mesh.isDistributed()) { auto & synchronizer = this->mesh.getElementSynchronizer(); this->registerSynchronizer(synchronizer, _gst_material_id); this->registerSynchronizer(synchronizer, _gst_smm_mass); this->registerSynchronizer(synchronizer, _gst_smm_stress); this->registerSynchronizer(synchronizer, _gst_smm_boundary); this->registerSynchronizer(synchronizer, _gst_for_dump); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); for (auto & internal : this->registered_internals) { delete internal.second; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setTimeStep(Real time_step, const ID & solver_id) { Model::setTimeStep(time_step, solver_id); #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialization */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilities */ void SolidMechanicsModel::initFullImpl(const ModelOptions & options) { material_index.initialize(mesh, _element_kind = _ek_not_defined, _default_value = UInt(-1), _with_nb_element = true); material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined, _with_nb_element = true); Model::initFullImpl(options); // initialize pbc if (this->pbc_pair.size() != 0) this->initPBC(); // initialize the materials if (this->parser.getLastParsedFile() != "") { this->instantiateMaterials(); } this->initMaterials(); this->initBC(*this, *displacement, *displacement_increment, *external_force); } /* -------------------------------------------------------------------------- */ TimeStepSolverType SolidMechanicsModel::getDefaultSolverType() const { return _tsst_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions SolidMechanicsModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_dynamic_lumped: { options.non_linear_solver_type = _nls_lumped; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case _tsst_static: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } case _tsst_dynamic: { if (this->method == _explicit_consistent_mass) { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; } else { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_trapezoidal_rule_2; options.solution_type["displacement"] = IntegrationScheme::_displacement; } break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } /* -------------------------------------------------------------------------- */ std::tuple<ID, TimeStepSolverType> SolidMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_lumped_mass: { return std::make_tuple("explicit_lumped", _tsst_dynamic_lumped); } case _explicit_consistent_mass: { return std::make_tuple("explicit", _tsst_dynamic); } case _static: { return std::make_tuple("static", _tsst_static); } case _implicit_dynamic: { return std::make_tuple("implicit", _tsst_dynamic); } default: return std::make_tuple("unknown", _tsst_not_defined); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType) { auto & dof_manager = this->getDOFManager(); /* ------------------------------------------------------------------------ */ // for alloc type of solvers this->allocNodalField(this->displacement, spatial_dimension, "displacement"); this->allocNodalField(this->previous_displacement, spatial_dimension, "previous_displacement"); this->allocNodalField(this->displacement_increment, spatial_dimension, "displacement_increment"); this->allocNodalField(this->internal_force, spatial_dimension, "internal_force"); this->allocNodalField(this->external_force, spatial_dimension, "external_force"); this->allocNodalField(this->blocked_dofs, spatial_dimension, "blocked_dofs"); this->allocNodalField(this->current_position, spatial_dimension, "current_position"); // initialize the current positions this->current_position->copy(this->mesh.getNodes()); /* ------------------------------------------------------------------------ */ if (!dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); dof_manager.registerDOFsIncrement("displacement", *this->displacement_increment); dof_manager.registerDOFsPrevious("displacement", *this->previous_displacement); } /* ------------------------------------------------------------------------ */ // for dynamic if (time_step_solver_type == _tsst_dynamic || time_step_solver_type == _tsst_dynamic_lumped) { this->allocNodalField(this->velocity, spatial_dimension, "velocity"); this->allocNodalField(this->acceleration, spatial_dimension, "acceleration"); if (!dof_manager.hasDOFsDerivatives("displacement", 1)) { dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity); dof_manager.registerDOFsDerivative("displacement", 2, *this->acceleration); } } } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleResidual() { AKANTU_DEBUG_IN(); /* ------------------------------------------------------------------------ */ // computes the internal forces this->assembleInternalForces(); /* ------------------------------------------------------------------------ */ this->getDOFManager().assembleToResidual("displacement", *this->external_force, 1); this->getDOFManager().assembleToResidual("displacement", *this->internal_force, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleResidual(const ID & residual_part) { AKANTU_DEBUG_IN(); if ("external" == residual_part) { this->getDOFManager().assembleToResidual("displacement", *this->external_force, 1); AKANTU_DEBUG_OUT(); return; } if ("internal" == residual_part) { this->getDOFManager().assembleToResidual("displacement", *this->internal_force, 1); AKANTU_DEBUG_OUT(); return; } AKANTU_CUSTOM_EXCEPTION( debug::SolverCallbackResidualPartUnknown(residual_part)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MatrixType SolidMechanicsModel::getMatrixType(const ID & matrix_id) { // \TODO check the materials to know what is the correct answer if (matrix_id == "C") return _mt_not_defined; return _symmetric; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } else if (matrix_id == "M") { this->assembleMass(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { this->assembleMassLumped(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::beforeSolveStep() { for (auto & material : materials) material->beforeSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::afterSolveStep() { for (auto & material : materials) material->afterSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::predictor() { ++displacement_release; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::corrector() { ++displacement_release; } /* -------------------------------------------------------------------------- */ /** * This function computes the internal forces as F_{int} = \int_{\Omega} N * \sigma d\Omega@f$ */ void SolidMechanicsModel::assembleInternalForces() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); this->internal_force->clear(); // compute the stresses of local elements AKANTU_DEBUG_INFO("Compute local stresses"); for (auto & material : materials) { material->computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ if (this->non_local_manager) this->non_local_manager->computeAllNonLocalStresses(); // communicate the stresses AKANTU_DEBUG_INFO("Send data for residual assembly"); this->asynchronousSynchronize(_gst_smm_stress); // assemble the forces due to local stresses AKANTU_DEBUG_INFO("Assemble residual for local elements"); for (auto & material : materials) { material->assembleInternalForces(_not_ghost); } // finalize communications AKANTU_DEBUG_INFO("Wait distant stresses"); this->waitEndSynchronize(_gst_smm_stress); // assemble the stresses due to ghost elements AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for (auto & material : materials) { material->assembleInternalForces(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); // Check if materials need to recompute the matrix bool need_to_reassemble = false; for (auto & material : materials) { need_to_reassemble |= material->hasStiffnessMatrixChanged(); } if (need_to_reassemble) { this->getDOFManager().getMatrix("K").clear(); // call compute stiffness matrix on each local elements for (auto & material : materials) { material->assembleStiffnessMatrix(_not_ghost); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { if (this->current_position_release == this->displacement_release) return; this->current_position->copy(this->mesh.getNodes()); auto cpos_it = this->current_position->begin(Model::spatial_dimension); auto cpos_end = this->current_position->end(Model::spatial_dimension); auto disp_it = this->displacement->begin(Model::spatial_dimension); for (; cpos_it != cpos_end; ++cpos_it, ++disp_it) { *cpos_it += *disp_it; } this->current_position_release = this->displacement_release; } /* -------------------------------------------------------------------------- */ const Array<Real> & SolidMechanicsModel::getCurrentPosition() { this->updateCurrentPosition(); return *this->current_position; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateDataForNonLocalCriterion( ElementTypeMapReal & criterion) { const ID field_name = criterion.getName(); for (auto & material : materials) { if (!material->isInternal<Real>(field_name, _ek_regular)) continue; for (auto ghost_type : ghost_types) { material->flattenInternal(field_name, criterion, ghost_type, _ek_regular); } } } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors mesh.getCommunicator().allReduce(min_dt, SynchronizerOperation::_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Real min_dt = std::numeric_limits<Real>::max(); this->updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, _ek_regular)) { elem.type = type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); auto mat_indexes = material_index(type, ghost_type).begin(); auto mat_loc_num = material_local_numbering(type, ghost_type).begin(); Array<Real> X(0, nb_nodes_per_element * Model::spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, type, _not_ghost); auto X_el = X.begin(Model::spatial_dimension, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++X_el, ++mat_indexes, ++mat_loc_num) { elem.element = *mat_loc_num; Real el_h = getFEEngine().getElementInradius(*X_el, type); Real el_c = this->materials[*mat_indexes]->getCelerity(elem); Real el_dt = el_h / el_c; min_dt = std::min(min_dt, el_dt); } } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy() { AKANTU_DEBUG_IN(); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); if (this->getDOFManager().hasLumpedMatrix("M")) { auto m_it = this->mass->begin(Model::spatial_dimension); auto m_end = this->mass->end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (UInt n = 0; m_it != m_end; ++n, ++m_it, ++v_it) { const Vector<Real> & v = *v_it; const Vector<Real> & m = *m_it; Real mv2 = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); // bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node; // && is_not_pbc_slave_node; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (m(i) > std::numeric_limits<Real>::epsilon()) mv2 += v(i) * v(i) * m(i); } } ekin += mv2; } } else if (this->getDOFManager().hasMatrix("M")) { Array<Real> Mv(nb_nodes, Model::spatial_dimension); this->getDOFManager().getMatrix("M").matVecMul(*this->velocity, Mv); auto mv_it = Mv.begin(Model::spatial_dimension); auto mv_end = Mv.end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (; mv_it != mv_end; ++mv_it, ++v_it) { ekin += v_it->dot(*mv_it); } } else { AKANTU_ERROR("No function called to assemble the mass matrix."); } mesh.getCommunicator().allReduce(ekin, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); Array<Real> vel_on_quad(nb_quadrature_points, Model::spatial_dimension); Array<UInt> filter_element(1, 1, index); getFEEngine().interpolateOnIntegrationPoints(*velocity, vel_on_quad, Model::spatial_dimension, type, _not_ghost, filter_element); auto vit = vel_on_quad.begin(Model::spatial_dimension); auto vend = vel_on_quad.end(Model::spatial_dimension); Vector<Real> rho_v2(nb_quadrature_points); Real rho = materials[material_index(type)(index)]->getRho(); for (UInt q = 0; vit != vend; ++vit, ++q) { rho_v2(q) = rho * vit->dot(*vit); } AKANTU_DEBUG_OUT(); return .5 * getFEEngine().integrate(rho_v2, type, index); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); auto ext_force_it = external_force->begin(Model::spatial_dimension); auto int_force_it = internal_force->begin(Model::spatial_dimension); auto boun_it = blocked_dofs->begin(Model::spatial_dimension); decltype(ext_force_it) incr_or_velo_it; if (this->method == _static) { incr_or_velo_it = this->displacement_increment->begin(Model::spatial_dimension); } else { incr_or_velo_it = this->velocity->begin(Model::spatial_dimension); } Real work = 0.; UInt nb_nodes = this->mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n, ++ext_force_it, ++int_force_it, ++boun_it, ++incr_or_velo_it) { const auto & int_force = *int_force_it; const auto & ext_force = *ext_force_it; const auto & boun = *boun_it; const auto & incr_or_velo = *incr_or_velo_it; bool is_local_node = this->mesh.isLocalOrMasterNode(n); // bool is_not_pbc_slave_node = !this->isPBCSlaveNode(n); bool count_node = is_local_node; // && is_not_pbc_slave_node; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (boun(i)) work -= int_force(i) * incr_or_velo(i); else work += ext_force(i) * incr_or_velo(i); } } } mesh.getCommunicator().allReduce(work, SynchronizerOperation::_sum); if (this->method != _static) work *= this->getTimeStep(); AKANTU_DEBUG_OUT(); return work; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(); } else if (energy_id == "external work") { return getExternalWork(); } Real energy = 0.; for (auto & material : materials) energy += material->getEnergy(energy_id); /// reduction sum over all processors mesh.getCommunicator().allReduce(energy, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id, const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(type, index); } UInt mat_index = this->material_index(type, _not_ghost)(index); UInt mat_loc_num = this->material_local_numbering(type, _not_ghost)(index); Real energy = this->materials[mat_index]->getEnergy(energy_id, type, mat_loc_num); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); this->material_index.initialize(mesh, _element_kind = _ek_not_defined, _with_nb_element = true, _default_value = UInt(-1)); this->material_local_numbering.initialize( mesh, _element_kind = _ek_not_defined, _with_nb_element = true, _default_value = UInt(-1)); ElementTypeMapArray<UInt> filter("new_element_filter", this->getID(), this->getMemoryID()); for (auto & elem : element_list) { if (!filter.exists(elem.type, elem.ghost_type)) filter.alloc(0, 1, elem.type, elem.ghost_type); filter(elem.type, elem.ghost_type).push_back(elem.element); } this->assignMaterialToElements(&filter); for (auto & material : materials) material->onElementsAdded(element_list, event); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved( const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) { for (auto & material : materials) { material->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if (displacement) { displacement->resize(nb_nodes, 0.); ++displacement_release; } if (mass) mass->resize(nb_nodes, 0.); if (velocity) velocity->resize(nb_nodes, 0.); if (acceleration) acceleration->resize(nb_nodes, 0.); if (external_force) external_force->resize(nb_nodes, 0.); if (internal_force) internal_force->resize(nb_nodes, 0.); if (blocked_dofs) blocked_dofs->resize(nb_nodes, 0.); if (current_position) current_position->resize(nb_nodes, 0.); if (previous_displacement) previous_displacement->resize(nb_nodes, 0.); if (displacement_increment) displacement_increment->resize(nb_nodes, 0.); for (auto & material : materials) { material->onNodesAdded(nodes_list, event); } need_to_reassemble_lumped_mass = true; need_to_reassemble_mass = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesRemoved(const Array<UInt> & /*element_list*/, const Array<UInt> & new_numbering, const RemovedNodesEvent & /*event*/) { if (displacement) { mesh.removeNodesFromArray(*displacement, new_numbering); ++displacement_release; } if (mass) mesh.removeNodesFromArray(*mass, new_numbering); if (velocity) mesh.removeNodesFromArray(*velocity, new_numbering); if (acceleration) mesh.removeNodesFromArray(*acceleration, new_numbering); if (internal_force) mesh.removeNodesFromArray(*internal_force, new_numbering); if (external_force) mesh.removeNodesFromArray(*external_force, new_numbering); if (blocked_dofs) mesh.removeNodesFromArray(*blocked_dofs, new_numbering); // if (increment_acceleration) // mesh.removeNodesFromArray(*increment_acceleration, new_numbering); if (displacement_increment) mesh.removeNodesFromArray(*displacement_increment, new_numbering); if (previous_displacement) mesh.removeNodesFromArray(*previous_displacement, new_numbering); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << Model::spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); if (velocity) velocity->printself(stream, indent + 2); if (acceleration) acceleration->printself(stream, indent + 2); if (mass) mass->printself(stream, indent + 2); external_force->printself(stream, indent + 2); internal_force->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + material information [" << std::endl; material_index.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + materials [" << std::endl; for (auto & material : materials) { material->printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeNonLocal() { this->non_local_manager->synchronize(*this, _gst_material_id); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type) { for (auto & mat : materials) { MaterialNonLocalInterface * mat_non_local; if ((mat_non_local = dynamic_cast<MaterialNonLocalInterface *>(mat.get())) == nullptr) continue; ElementTypeMapArray<Real> quadrature_points_coordinates( "quadrature_points_coordinates_tmp_nl", this->id, this->memory_id); quadrature_points_coordinates.initialize(this->getFEEngine(), _nb_component = spatial_dimension, _ghost_type = ghost_type); for (auto & type : quadrature_points_coordinates.elementTypes( Model::spatial_dimension, ghost_type)) { this->getFEEngine().computeIntegrationPointsCoordinates( quadrature_points_coordinates(type, ghost_type), type, ghost_type); } mat_non_local->initMaterialNonLocal(); mat_non_local->insertIntegrationPointsInNeighborhoods( ghost_type, quadrature_points_coordinates); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeNonLocalStresses( const GhostType & ghost_type) { for (auto & mat : materials) { if (dynamic_cast<MaterialNonLocalInterface *>(mat.get()) == nullptr) continue; auto & mat_non_local = dynamic_cast<MaterialNonLocalInterface &>(*mat); mat_non_local.computeNonLocalStresses(ghost_type); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & material : materials) { if (material->isInternal<Real>(field_name, kind)) material->flattenInternal(field_name, internal_flat, ghost_type, kind); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateNonLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & mat : materials) { if (dynamic_cast<MaterialNonLocalInterface *>(mat.get()) == nullptr) continue; auto & mat_non_local = dynamic_cast<MaterialNonLocalInterface &>(*mat); mat_non_local.updateNonLocalInternals(internal_flat, field_name, ghost_type, kind); } } /* -------------------------------------------------------------------------- */ FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) { return dynamic_cast<FEEngine &>( getFEEngineClassBoundary<MyFEEngineType>(name)); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::splitElementByMaterial( const Array<Element> & elements, std::vector<Array<Element>> & elements_per_mat) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; const Array<UInt> * mat_indexes = nullptr; const Array<UInt> * mat_loc_num = nullptr; for (const auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; mat_indexes = &(this->material_index(el.type, el.ghost_type)); mat_loc_num = &(this->material_local_numbering(el.type, el.ghost_type)); } Element mat_el = el; mat_el.element = (*mat_loc_num)(el.element); elements_per_mat[(*mat_indexes)(el.element)].push_back(mat_el); } } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModel::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes_per_element = 0; for (const Element & el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch (tag) { case _gst_material_id: { size += elements.size() * sizeof(UInt); break; } case _gst_smm_mass: { size += nb_nodes_per_element * sizeof(Real) * Model::spatial_dimension; // mass vector break; } case _gst_smm_for_gradu: { size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real); // displacement break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * Model::spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } case _gst_for_dump: { // displacement, velocity, acceleration, residual, force size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real) * 5; break; } default: {} } if (tag != _gst_material_id) { splitByMaterial(elements, [&](auto && mat, auto && elements) { size += mat.getNbData(elements, tag); }); } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); switch (tag) { case _gst_material_id: { this->packElementalDataHelper(material_index, buffer, elements, false, getFEEngine()); break; } case _gst_smm_mass: { packNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { packNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_for_dump: { packNodalDataHelper(*displacement, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*acceleration, buffer, elements, mesh); packNodalDataHelper(*internal_force, buffer, elements, mesh); packNodalDataHelper(*external_force, buffer, elements, mesh); break; } case _gst_smm_boundary: { packNodalDataHelper(*external_force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.packData(buffer, elements, tag); }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); switch (tag) { case _gst_material_id: { for (auto && element : elements) { UInt recv_mat_index; buffer >> recv_mat_index; UInt & mat_index = material_index(element); if (mat_index != UInt(-1)) continue; // add ghosts element to the correct material mat_index = recv_mat_index; UInt index = materials[mat_index]->addElement(element); material_local_numbering(element) = index; } break; } case _gst_smm_mass: { unpackNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_for_dump: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*acceleration, buffer, elements, mesh); unpackNodalDataHelper(*internal_force, buffer, elements, mesh); unpackNodalDataHelper(*external_force, buffer, elements, mesh); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*external_force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.unpackData(buffer, elements, tag); }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModel::getNbData(const Array<UInt> & dofs, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch (tag) { case _gst_smm_uv: { size += sizeof(Real) * Model::spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * Model::spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * Model::spatial_dimension; break; } case _gst_for_dump: { size += sizeof(Real) * Model::spatial_dimension * 5; break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size * dofs.size(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); switch (tag) { case _gst_smm_uv: { packDOFDataHelper(*displacement, buffer, dofs); packDOFDataHelper(*velocity, buffer, dofs); break; } case _gst_smm_res: { packDOFDataHelper(*internal_force, buffer, dofs); break; } case _gst_smm_mass: { packDOFDataHelper(*mass, buffer, dofs); break; } case _gst_for_dump: { packDOFDataHelper(*displacement, buffer, dofs); packDOFDataHelper(*velocity, buffer, dofs); packDOFDataHelper(*acceleration, buffer, dofs); packDOFDataHelper(*internal_force, buffer, dofs); packDOFDataHelper(*external_force, buffer, dofs); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); switch (tag) { case _gst_smm_uv: { unpackDOFDataHelper(*displacement, buffer, dofs); unpackDOFDataHelper(*velocity, buffer, dofs); break; } case _gst_smm_res: { unpackDOFDataHelper(*internal_force, buffer, dofs); break; } case _gst_smm_mass: { unpackDOFDataHelper(*mass, buffer, dofs); break; } case _gst_for_dump: { unpackDOFDataHelper(*displacement, buffer, dofs); unpackDOFDataHelper(*velocity, buffer, dofs); unpackDOFDataHelper(*acceleration, buffer, dofs); unpackDOFDataHelper(*internal_force, buffer, dofs); unpackDOFDataHelper(*external_force, buffer, dofs); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index 57e489704..37c45ef56 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,559 +1,559 @@ /** * @file solid_mechanics_model.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 27 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Model of Solid Mechanics * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "data_accessor.hh" #include "fe_engine.hh" #include "model.hh" #include "non_local_manager.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_HH__ namespace akantu { class Material; class MaterialSelector; class DumperIOHelper; class NonLocalManager; template <ElementKind kind, class IntegrationOrderFunctor> class IntegratorGauss; template <ElementKind kind> class ShapeLagrange; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ class SolidMechanicsModel : public Model, public DataAccessor<Element>, public DataAccessor<UInt>, public BoundaryCondition<SolidMechanicsModel>, public NonLocalManagerCallback, public EventHandlerManager<SolidMechanicsModelEventHandler> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewMaterialElementsEvent : public NewElementsEvent { public: AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array<UInt> &); AKANTU_GET_MACRO(MaterialList, material, const Array<UInt> &); protected: Array<UInt> material; }; using MyFEEngineType = FEEngineTemplate<IntegratorGauss, ShapeLagrange>; protected: using EventManager = EventHandlerManager<SolidMechanicsModelEventHandler>; public: SolidMechanicsModel( Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0, const ModelType model_type = ModelType::_solid_mechanics_model); ~SolidMechanicsModel() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize completely the model void initFullImpl( const ModelOptions & options = SolidMechanicsModelOptions()) override; /// initialize all internal arrays for materials virtual void initMaterials(); /// initialize the model void initModel() override; /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; /// get some default values for derived classes std::tuple<ID, TimeStepSolverType> getDefaultSolverID(const AnalysisMethod & method) override; /* ------------------------------------------------------------------------ */ /* Solver interface */ /* ------------------------------------------------------------------------ */ public: /// assembles the stiffness matrix, virtual void assembleStiffnessMatrix(); /// assembles the internal forces in the array internal_forces virtual void assembleInternalForces(); protected: /// callback for the solver, this adds f_{ext} - f_{int} to the residual void assembleResidual() override; /// callback for the solver, this adds f_{ext} or f_{int} to the residual void assembleResidual(const ID & residual_part) override; bool canSplitResidual() override { return true; } /// get the type of matrix needed MatrixType getMatrixType(const ID & matrix_id) override; /// callback for the solver, this assembles different matrices void assembleMatrix(const ID & matrix_id) override; /// callback for the solver, this assembles the stiffness matrix void assembleLumpedMatrix(const ID & matrix_id) override; /// callback for the solver, this is called at beginning of solve void predictor() override; /// callback for the solver, this is called at end of solve void corrector() override; /// callback for the solver, this is called at beginning of solve void beforeSolveStep() override; /// callback for the solver, this is called at end of solve void afterSolveStep() override; /// Callback for the model to instantiate the matricees when needed void initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType non_linear_solver_type) override; protected: /* ------------------------------------------------------------------------ */ TimeStepSolverType getDefaultSolverType() const override; /* ------------------------------------------------------------------------ */ ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const override; public: bool isDefaultSolverExplicit() { return method == _explicit_lumped_mass || method == _explicit_consistent_mass; } protected: /// update the current position vector void updateCurrentPosition(); /* ------------------------------------------------------------------------ */ /* Materials (solid_mechanics_model_material.cc) */ /* ------------------------------------------------------------------------ */ public: /// register an empty material of a given type Material & registerNewMaterial(const ID & mat_name, const ID & mat_type, const ID & opt_param); /// reassigns materials depending on the material selector virtual void reassignMaterial(); /// apply a constant eigen_grad_u on all quadrature points of a given material virtual void applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u, const ID & material_name, const GhostType ghost_type = _not_ghost); protected: /// register a material in the dynamic database Material & registerNewMaterial(const ParserSection & mat_section); /// read the material files to instantiate all the materials void instantiateMaterials(); /// set the element_id_by_material and add the elements to the good materials virtual void assignMaterialToElements(const ElementTypeMapArray<UInt> * filter = nullptr); /* ------------------------------------------------------------------------ */ /* Mass (solid_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); protected: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); /// fill a vector of rho void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type); /// compute the kinetic energy Real getKineticEnergy(); Real getKineticEnergy(const ElementType & type, UInt index); /// compute the external work (for impose displacement, the velocity should be /// given too) Real getExternalWork(); /* ------------------------------------------------------------------------ */ /* NonLocalManager inherited members */ /* ------------------------------------------------------------------------ */ protected: void initializeNonLocal() override; void updateDataForNonLocalCriterion(ElementTypeMapReal & criterion) override; void computeNonLocalStresses(const GhostType & ghost_type) override; void insertIntegrationPointsInNeighborhoods(const GhostType & ghost_type) override; /// update the values of the non local internal void updateLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) override; /// copy the results of the averaging in the materials void updateNonLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) override; /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; UInt getNbData(const Array<UInt> & dofs, const SynchronizationTag & tag) const override; void packData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) const override; void unpackData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) override; protected: void splitElementByMaterial(const Array<Element> & elements, std::vector<Array<Element>> & elements_per_mat) const; template <typename Operation> void splitByMaterial(const Array<Element> & elements, Operation && op) const; /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: void onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) override; void onNodesRemoved(const Array<UInt> & element_list, const Array<UInt> & new_numbering, const RemovedNodesEvent & event) override; void onElementsAdded(const Array<Element> & nodes_list, const NewElementsEvent & event) override; void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; void onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) override{}; /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ public: virtual void onDump(); //! decide wether a field is a material internal or not bool isInternal(const std::string & field_name, const ElementKind & element_kind); #ifndef SWIG //! give the amount of data per element virtual ElementTypeMap<UInt> getInternalDataPerElem(const std::string & field_name, const ElementKind & kind); //! flatten a given material internal field ElementTypeMapArray<Real> & flattenInternal(const std::string & field_name, const ElementKind & kind, const GhostType ghost_type = _not_ghost); //! flatten all the registered material internals void flattenAllRegisteredInternals(const ElementKind & kind); #endif dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) override; dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) override; dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & kind) override; virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); void dump() override; virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt); /// set the value of the time step void setTimeStep(Real time_step, const ID & solver_id = "") override; /// get the value of the conversion from forces/ mass to acceleration AKANTU_GET_MACRO(F_M2A, f_m2a, Real); /// set the value of the conversion from forces/ mass to acceleration AKANTU_SET_MACRO(F_M2A, f_m2a, Real); /// get the SolidMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array<Real> &); /// get the SolidMechanicsModel::previous_displacement vector AKANTU_GET_MACRO(PreviousDisplacement, *previous_displacement, Array<Real> &); /// get the SolidMechanicsModel::current_position vector \warn only consistent /// after a call to SolidMechanicsModel::updateCurrentPosition const Array<Real> & getCurrentPosition(); /// get the SolidMechanicsModel::increment vector \warn only consistent if /// SolidMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *displacement_increment, Array<Real> &); /// get the lumped SolidMechanicsModel::mass vector AKANTU_GET_MACRO(Mass, *mass, Array<Real> &); /// get the SolidMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array<Real> &); /// get the SolidMechanicsModel::acceleration vector, updated by /// SolidMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array<Real> &); /// get the SolidMechanicsModel::force vector (external forces) AKANTU_GET_MACRO(Force, *external_force, Array<Real> &); /// get the SolidMechanicsModel::internal_force vector (internal forces) AKANTU_GET_MACRO(InternalForce, *internal_force, Array<Real> &); /// get the SolidMechanicsModel::blocked_dofs vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &); /// get the value of the SolidMechanicsModel::increment_flag AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool); /// get a particular material (by material index) inline Material & getMaterial(UInt mat_index); /// get a particular material (by material index) inline const Material & getMaterial(UInt mat_index) const; /// get a particular material (by material name) inline Material & getMaterial(const std::string & name); /// get a particular material (by material name) inline const Material & getMaterial(const std::string & name) const; /// get a particular material id from is name inline UInt getMaterialIndex(const std::string & name) const; /// give the number of materials inline UInt getNbMaterials() const { return materials.size(); } /// give the material internal index from its id Int getInternalIndexFromID(const ID & id) const; /// compute the stable time step Real getStableTimeStep(); /// get the energies Real getEnergy(const std::string & energy_id); /// compute the energy for energy Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index); AKANTU_GET_MACRO(MaterialByElement, material_index, const ElementTypeMapArray<UInt> &); /// vectors containing local material element index for each global element /// index AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialByElement, material_index, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialByElement, material_index, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialLocalNumbering, material_local_numbering, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialLocalNumbering, material_local_numbering, UInt); AKANTU_GET_MACRO_NOT_CONST(MaterialSelector, *material_selector, MaterialSelector &); AKANTU_SET_MACRO(MaterialSelector, material_selector, std::shared_ptr<MaterialSelector>); /// Access the non_local_manager interface AKANTU_GET_MACRO(NonLocalManager, *non_local_manager, NonLocalManager &); /// get the FEEngine object to integrate or interpolate on the boundary FEEngine & getFEEngineBoundary(const ID & name = "") override; protected: friend class Material; protected: /// compute the stable time step Real getStableTimeStep(const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array<Real> * displacement; UInt displacement_release{0}; /// displacements array at the previous time step (used in finite deformation) Array<Real> * previous_displacement{nullptr}; /// increment of displacement Array<Real> * displacement_increment{nullptr}; /// lumped mass array Array<Real> * mass{nullptr}; /// Check if materials need to recompute the mass array bool need_to_reassemble_lumped_mass{true}; /// Check if materials need to recompute the mass matrix bool need_to_reassemble_mass{true}; /// velocities array Array<Real> * velocity{nullptr}; /// accelerations array Array<Real> * acceleration{nullptr}; /// accelerations array // Array<Real> * increment_acceleration; /// external forces array Array<Real> * external_force{nullptr}; /// internal forces array Array<Real> * internal_force{nullptr}; /// array specifing if a degree of freedom is blocked or not Array<bool> * blocked_dofs{nullptr}; /// array of current position used during update residual Array<Real> * current_position{nullptr}; UInt current_position_release{0}; /// Arrays containing the material index for each element ElementTypeMapArray<UInt> material_index; /// Arrays containing the position in the element filter of the material /// (material's local numbering) ElementTypeMapArray<UInt> material_local_numbering; /// list of used materials std::vector<std::unique_ptr<Material>> materials; /// mapping between material name and material internal id std::map<std::string, UInt> materials_names_to_id; /// class defining of to choose a material std::shared_ptr<MaterialSelector> material_selector; /// flag defining if the increment must be computed or not bool increment_flag; /// tells if the material are instantiated bool are_materials_instantiated; using flatten_internal_map = std::map<std::pair<std::string, ElementKind>, ElementTypeMapArray<Real> *>; /// map a registered internals to be flattened for dump purposes flatten_internal_map registered_internals; /// non local manager std::unique_ptr<NonLocalManager> non_local_manager; }; /* -------------------------------------------------------------------------- */ namespace BC { namespace Neumann { using FromStress = FromHigherDim; using FromTraction = FromSameDim; } // namespace Neumann } // namespace BC } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "parser.hh" #include "solid_mechanics_model_inline_impl.cc" #include "solid_mechanics_model_tmpl.hh" /* -------------------------------------------------------------------------- */ #endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc index 63396a1b8..9f1a72dd2 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc @@ -1,611 +1,612 @@ /** * @file fragment_manager.cc * + * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Thu Jan 23 2014 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Group manager to handle fragments * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fragment_manager.hh" #include "aka_iterators.hh" #include "communicator.hh" #include "material_cohesive.hh" #include "mesh_iterators.hh" #include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <functional> #include <numeric> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ FragmentManager::FragmentManager(SolidMechanicsModelCohesive & model, bool dump_data, const ID & id, const MemoryID & memory_id) : GroupManager(model.getMesh(), id, memory_id), model(model), mass_center(0, model.getSpatialDimension(), "mass_center"), mass(0, model.getSpatialDimension(), "mass"), velocity(0, model.getSpatialDimension(), "velocity"), inertia_moments(0, model.getSpatialDimension(), "inertia_moments"), principal_directions( 0, model.getSpatialDimension() * model.getSpatialDimension(), "principal_directions"), quad_coordinates("quad_coordinates", id), mass_density("mass_density", id), nb_elements_per_fragment(0, 1, "nb_elements_per_fragment"), dump_data(dump_data) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); /// compute quadrature points' coordinates quad_coordinates.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost); // mesh.initElementTypeMapArray(quad_coordinates, spatial_dimension, // spatial_dimension, _not_ghost); model.getFEEngine().interpolateOnIntegrationPoints(model.getMesh().getNodes(), quad_coordinates); /// store mass density per quadrature point mass_density.initialize(mesh, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost); // mesh.initElementTypeMapArray(mass_density, 1, spatial_dimension, // _not_ghost); storeMassDensityPerIntegrationPoint(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ class CohesiveElementFilter : public GroupManager::ClusteringFilter { public: CohesiveElementFilter(const SolidMechanicsModelCohesive & model, const Real max_damage = 1.) : model(model), is_unbroken(max_damage) {} bool operator()(const Element & el) const override { if (Mesh::getKind(el.type) == _ek_regular) return true; const Array<UInt> & mat_indexes = model.getMaterialByElement(el.type, el.ghost_type); const Array<UInt> & mat_loc_num = model.getMaterialLocalNumbering(el.type, el.ghost_type); const auto & mat = static_cast<const MaterialCohesive &>( model.getMaterial(mat_indexes(el.element))); UInt el_index = mat_loc_num(el.element); UInt nb_quad_per_element = model.getFEEngine("CohesiveFEEngine") .getNbIntegrationPoints(el.type, el.ghost_type); const Array<Real> & damage_array = mat.getDamage(el.type, el.ghost_type); AKANTU_DEBUG_ASSERT(nb_quad_per_element * el_index < damage_array.size(), "This quadrature point is out of range"); const Real * element_damage = damage_array.storage() + nb_quad_per_element * el_index; UInt unbroken_quads = std::count_if( element_damage, element_damage + nb_quad_per_element, is_unbroken); if (unbroken_quads > 0) return true; return false; } private: struct IsUnbrokenFunctor { IsUnbrokenFunctor(const Real & max_damage) : max_damage(max_damage) {} bool operator()(const Real & x) { return x < max_damage; } const Real max_damage; }; const SolidMechanicsModelCohesive & model; const IsUnbrokenFunctor is_unbroken; }; /* -------------------------------------------------------------------------- */ void FragmentManager::buildFragments(Real damage_limit) { AKANTU_DEBUG_IN(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) ElementSynchronizer * cohesive_synchronizer = const_cast<ElementSynchronizer *>(model.getCohesiveSynchronizer()); if (cohesive_synchronizer) { cohesive_synchronizer->computeBufferSize(model, _gst_smmc_damage); cohesive_synchronizer->asynchronousSynchronize(model, _gst_smmc_damage); cohesive_synchronizer->waitEndSynchronize(model, _gst_smmc_damage); } #endif auto & mesh_facets = const_cast<Mesh &>(mesh.getMeshFacets()); UInt spatial_dimension = model.getSpatialDimension(); std::string fragment_prefix("fragment"); /// generate fragments global_nb_fragment = createClusters(spatial_dimension, mesh_facets, fragment_prefix, CohesiveElementFilter(model, damage_limit)); nb_fragment = getNbElementGroups(spatial_dimension); fragment_index.resize(nb_fragment); UInt * fragment_index_it = fragment_index.storage(); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { /// get fragment index std::string fragment_index_string = it->first.substr(fragment_prefix.size() + 1); std::stringstream sstr(fragment_index_string.c_str()); sstr >> *fragment_index_it; AKANTU_DEBUG_ASSERT(!sstr.fail(), "fragment_index is not an integer"); } /// compute fragments' mass computeMass(); if (dump_data) { createDumpDataArray(fragment_index, "fragments", true); createDumpDataArray(mass, "fragments mass"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeMass() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); /// create a unit field per quadrature point, since to compute mass /// it's neccessary to integrate only density ElementTypeMapArray<Real> unit_field("unit_field", id); unit_field.initialize(model.getFEEngine(), _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost, _default_value = 1.); // mesh.initElementTypeMapArray(unit_field, spatial_dimension, // spatial_dimension, // _not_ghost); // ElementTypeMapArray<Real>::type_iterator it = // unit_field.firstType(spatial_dimension, _not_ghost, _ek_regular); // ElementTypeMapArray<Real>::type_iterator end = // unit_field.lastType(spatial_dimension, _not_ghost, _ek_regular); // for (; it != end; ++it) { // ElementType type = *it; // Array<Real> & field_array = unit_field(type); // UInt nb_element = mesh.getNbElement(type); // UInt nb_quad_per_element = // model.getFEEngine().getNbIntegrationPoints(type); // field_array.resize(nb_element * nb_quad_per_element); // field_array.set(1.); // } integrateFieldOnFragments(unit_field, mass); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeCenterOfMass() { AKANTU_DEBUG_IN(); /// integrate position multiplied by density integrateFieldOnFragments(quad_coordinates, mass_center); /// divide it by the fragments' mass Real * mass_storage = mass.storage(); Real * mass_center_storage = mass_center.storage(); UInt total_components = mass_center.size() * mass_center.getNbComponent(); for (UInt i = 0; i < total_components; ++i) mass_center_storage[i] /= mass_storage[i]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeVelocity() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); /// compute velocity per quadrature point ElementTypeMapArray<Real> velocity_field("velocity_field", id); velocity_field.initialize( model.getFEEngine(), _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost); // mesh.initElementTypeMapArray(velocity_field, spatial_dimension, // spatial_dimension, _not_ghost); model.getFEEngine().interpolateOnIntegrationPoints(model.getVelocity(), velocity_field); /// integrate on fragments integrateFieldOnFragments(velocity_field, velocity); /// divide it by the fragments' mass Real * mass_storage = mass.storage(); Real * velocity_storage = velocity.storage(); UInt total_components = velocity.size() * velocity.getNbComponent(); for (UInt i = 0; i < total_components; ++i) velocity_storage[i] /= mass_storage[i]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Given the distance @f$ \mathbf{r} @f$ between a quadrature point * and its center of mass, the moment of inertia is computed as \f[ * I_\mathrm{CM} = \mathrm{tr}(\mathbf{r}\mathbf{r}^\mathrm{T}) * \mathbf{I} - \mathbf{r}\mathbf{r}^\mathrm{T} \f] for more * information check Wikipedia * (http://en.wikipedia.org/wiki/Moment_of_inertia#Identities_for_a_skew-symmetric_matrix) * */ void FragmentManager::computeInertiaMoments() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); computeCenterOfMass(); /// compute local coordinates products with respect to the center of match ElementTypeMapArray<Real> moments_coords("moments_coords", id); moments_coords.initialize(model.getFEEngine(), _nb_component = spatial_dimension * spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost, _default_value = 1.); // mesh.initElementTypeMapArray(moments_coords, // spatial_dimension * spatial_dimension, // spatial_dimension, _not_ghost); // /// resize the by element type // ElementTypeMapArray<Real>::type_iterator it = // moments_coords.firstType(spatial_dimension, _not_ghost, _ek_regular); // ElementTypeMapArray<Real>::type_iterator end = // moments_coords.lastType(spatial_dimension, _not_ghost, _ek_regular); // for (; it != end; ++it) { // ElementType type = *it; // Array<Real> & field_array = moments_coords(type); // UInt nb_element = mesh.getNbElement(type); // UInt nb_quad_per_element = // model.getFEEngine().getNbIntegrationPoints(type); // field_array.resize(nb_element * nb_quad_per_element); // } /// compute coordinates auto mass_center_it = mass_center.begin(spatial_dimension); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++mass_center_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); /// loop over elements of the fragment for (auto type : el_list.elementTypes(spatial_dimension, _not_ghost, _ek_regular)) { UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); Array<Real> & moments_coords_array = moments_coords(type); const Array<Real> & quad_coordinates_array = quad_coordinates(type); const Array<UInt> & el_list_array = el_list(type); Array<Real>::matrix_iterator moments_begin = moments_coords_array.begin(spatial_dimension, spatial_dimension); auto quad_coordinates_begin = quad_coordinates_array.begin(spatial_dimension); Vector<Real> relative_coords(spatial_dimension); for (UInt el = 0; el < el_list_array.size(); ++el) { UInt global_el = el_list_array(el); /// loop over quadrature points for (UInt q = 0; q < nb_quad_per_element; ++q) { UInt global_q = global_el * nb_quad_per_element + q; Matrix<Real> moments_matrix = moments_begin[global_q]; const Vector<Real> & quad_coord_vector = quad_coordinates_begin[global_q]; /// to understand this read the documentation written just /// before this function relative_coords = quad_coord_vector; relative_coords -= *mass_center_it; moments_matrix.outerProduct(relative_coords, relative_coords); Real trace = moments_matrix.trace(); moments_matrix *= -1.; moments_matrix += Matrix<Real>::eye(spatial_dimension, trace); } } } } /// integrate moments Array<Real> integrated_moments(global_nb_fragment, spatial_dimension * spatial_dimension); integrateFieldOnFragments(moments_coords, integrated_moments); /// compute and store principal moments inertia_moments.resize(global_nb_fragment); principal_directions.resize(global_nb_fragment); Array<Real>::matrix_iterator integrated_moments_it = integrated_moments.begin(spatial_dimension, spatial_dimension); auto inertia_moments_it = inertia_moments.begin(spatial_dimension); Array<Real>::matrix_iterator principal_directions_it = principal_directions.begin(spatial_dimension, spatial_dimension); for (UInt frag = 0; frag < global_nb_fragment; ++frag, ++integrated_moments_it, ++inertia_moments_it, ++principal_directions_it) { integrated_moments_it->eig(*inertia_moments_it, *principal_directions_it); } if (dump_data) createDumpDataArray(inertia_moments, "moments of inertia"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeAllData() { AKANTU_DEBUG_IN(); buildFragments(); computeVelocity(); computeInertiaMoments(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::storeMassDensityPerIntegrationPoint() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator end = mesh.lastType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; Array<Real> & mass_density_array = mass_density(type); UInt nb_element = mesh.getNbElement(type); UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); mass_density_array.resize(nb_element * nb_quad_per_element); const Array<UInt> & mat_indexes = model.getMaterialByElement(type); Real * mass_density_it = mass_density_array.storage(); /// store mass_density for each element and quadrature point for (UInt el = 0; el < nb_element; ++el) { Material & mat = model.getMaterial(mat_indexes(el)); for (UInt q = 0; q < nb_quad_per_element; ++q, ++mass_density_it) *mass_density_it = mat.getRho(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::integrateFieldOnFragments( ElementTypeMapArray<Real> & field, Array<Real> & output) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); UInt nb_component = output.getNbComponent(); /// integration part output.resize(global_nb_fragment); output.clear(); UInt * fragment_index_it = fragment_index.storage(); auto output_begin = output.begin(nb_component); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); /// loop over elements of the fragment for (auto type : el_list.elementTypes(spatial_dimension, _not_ghost, _ek_regular)) { UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); const Array<Real> & density_array = mass_density(type); Array<Real> & field_array = field(type); const Array<UInt> & elements = el_list(type); UInt nb_element = elements.size(); /// generate array to be integrated by filtering fragment's elements Array<Real> integration_array(elements.size() * nb_quad_per_element, nb_component); Array<Real>::matrix_iterator int_array_it = integration_array.begin_reinterpret(nb_quad_per_element, nb_component, nb_element); Array<Real>::matrix_iterator int_array_end = integration_array.end_reinterpret(nb_quad_per_element, nb_component, nb_element); Array<Real>::matrix_iterator field_array_begin = field_array.begin_reinterpret(nb_quad_per_element, nb_component, field_array.size() / nb_quad_per_element); auto density_array_begin = density_array.begin_reinterpret( nb_quad_per_element, density_array.size() / nb_quad_per_element); for (UInt el = 0; int_array_it != int_array_end; ++int_array_it, ++el) { UInt global_el = elements(el); *int_array_it = field_array_begin[global_el]; /// multiply field by density const Vector<Real> & density_vector = density_array_begin[global_el]; for (UInt i = 0; i < nb_quad_per_element; ++i) { for (UInt j = 0; j < nb_component; ++j) { (*int_array_it)(i, j) *= density_vector(i); } } } /// integrate the field over the fragment Array<Real> integrated_array(elements.size(), nb_component); model.getFEEngine().integrate(integration_array, integrated_array, nb_component, type, _not_ghost, elements); /// sum over all elements and store the result Vector<Real> output_tmp(output_begin[*fragment_index_it]); output_tmp += std::accumulate(integrated_array.begin(nb_component), integrated_array.end(nb_component), Vector<Real>(nb_component)); } } /// sum output over all processors const Communicator & comm = mesh.getCommunicator(); comm.allReduce(output, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeNbElementsPerFragment() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); nb_elements_per_fragment.resize(global_nb_fragment); nb_elements_per_fragment.clear(); UInt * fragment_index_it = fragment_index.storage(); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); /// loop over elements of the fragment for (auto type : el_list.elementTypes(spatial_dimension, _not_ghost, _ek_regular)) { UInt nb_element = el_list(type).size(); nb_elements_per_fragment(*fragment_index_it) += nb_element; } } /// sum values over all processors const auto & comm = mesh.getCommunicator(); comm.allReduce(nb_elements_per_fragment, SynchronizerOperation::_sum); if (dump_data) createDumpDataArray(nb_elements_per_fragment, "elements per fragment"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void FragmentManager::createDumpDataArray(Array<T> & data, std::string name, bool fragment_index_output) { AKANTU_DEBUG_IN(); if (data.size() == 0) return; auto & mesh_not_const = const_cast<Mesh &>(mesh); auto && spatial_dimension = mesh.getSpatialDimension(); auto && nb_component = data.getNbComponent(); auto && data_begin = data.begin(nb_component); auto fragment_index_it = fragment_index.begin(); /// loop over fragments for (const auto & fragment : ElementGroupsIterable(*this)) { const auto & fragment_idx = *fragment_index_it; /// loop over cluster types for (auto & type : fragment.elementTypes(spatial_dimension)) { /// init mesh data auto & mesh_data = mesh_not_const.getDataPointer<T>( name, type, _not_ghost, nb_component); auto mesh_data_begin = mesh_data.begin(nb_component); /// fill mesh data for (const auto & elem : fragment.getElements(type)) { Vector<T> md_tmp = mesh_data_begin[elem]; if (fragment_index_output) { md_tmp(0) = fragment_idx; } else { md_tmp = data_begin[fragment_idx]; } } } } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.hh index 74f676cd4..eaf2025f7 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.hh @@ -1,169 +1,169 @@ /** * @file fragment_manager.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Thu Jan 23 2014 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Thu Jul 06 2017 * * @brief Group manager to handle fragments * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "group_manager.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FRAGMENT_MANAGER_HH__ #define __AKANTU_FRAGMENT_MANAGER_HH__ namespace akantu { class SolidMechanicsModelCohesive; } namespace akantu { /* -------------------------------------------------------------------------- */ class FragmentManager : public GroupManager { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: FragmentManager(SolidMechanicsModelCohesive & model, bool dump_data = true, const ID & id = "fragment_manager", const MemoryID & memory_id = 0); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ private: /// store mass density per integration point void storeMassDensityPerIntegrationPoint(); /// integrate an elemental field multiplied by density on global /// fragments void integrateFieldOnFragments(ElementTypeMapArray<Real> & field, Array<Real> & output); /// compute fragments' mass void computeMass(); /// create dump data for a single array template <typename T> void createDumpDataArray(Array<T> & data, std::string name, bool fragment_index_output = false); public: /// build fragment list (cohesive elements are considered broken if /// damage >= damage_limit) void buildFragments(Real damage_limit = 1.); /// compute fragments' center of mass void computeCenterOfMass(); /// compute fragments' velocity void computeVelocity(); /// computes principal moments of inertia with respect to the center /// of mass of each fragment void computeInertiaMoments(); /// compute all fragments' data void computeAllData(); /// compute number of elements per fragment void computeNbElementsPerFragment(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get number of fragments AKANTU_GET_MACRO(NbFragment, global_nb_fragment, UInt); /// get fragments' mass AKANTU_GET_MACRO(Mass, mass, const Array<Real> &); /// get fragments' center of mass AKANTU_GET_MACRO(CenterOfMass, mass_center, const Array<Real> &); /// get fragments' velocity AKANTU_GET_MACRO(Velocity, velocity, const Array<Real> &); /// get fragments' principal moments of inertia AKANTU_GET_MACRO(MomentsOfInertia, inertia_moments, const Array<Real> &); /// get fragments' principal directions AKANTU_GET_MACRO(PrincipalDirections, principal_directions, const Array<Real> &); /// get number of elements per fragment AKANTU_GET_MACRO(NbElementsPerFragment, nb_elements_per_fragment, const Array<UInt> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// local_fragment index Array<UInt> fragment_index; /// global number of fragments (parallel simulations) UInt global_nb_fragment; /// number of fragments UInt nb_fragment; /// cohesive solid mechanics model associated SolidMechanicsModelCohesive & model; /// fragments' center of mass Array<Real> mass_center; /// fragments' mass Array<Real> mass; /// fragments' velocity Array<Real> velocity; /// fragments' principal moments of inertia with respect to the /// center of mass Array<Real> inertia_moments; /// fragments' principal directions Array<Real> principal_directions; /// quadrature points' coordinates ElementTypeMapArray<Real> quad_coordinates; /// mass density per quadrature point ElementTypeMapArray<Real> mass_density; /// fragment filter Array<UInt> nb_elements_per_fragment; /// dump data bool dump_data; }; } // akantu #endif /* __AKANTU_FRAGMENT_MANAGER_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.cc index cfed39f0e..3f052a5fb 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.cc @@ -1,159 +1,159 @@ /** * @file material_selector_cohesive.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Dec 11 2015 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Mon Dec 18 2017 * * @brief Material selector for cohesive elements * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_selector_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ DefaultMaterialCohesiveSelector::DefaultMaterialCohesiveSelector( const SolidMechanicsModelCohesive & model) : facet_material(model.getFacetMaterial()), mesh(model.getMesh()) { // backward compatibility v3: to get the former behavior back when the user // creates its own selector this->fallback_selector = std::make_shared<DefaultMaterialSelector>(model.getMaterialByElement()); } /* -------------------------------------------------------------------------- */ UInt DefaultMaterialCohesiveSelector::operator()(const Element & element) { if (Mesh::getKind(element.type) == _ek_cohesive) { try { const Array<Element> & cohesive_el_to_facet = mesh.getMeshFacets().getSubelementToElement(element.type, element.ghost_type); bool third_dimension = (mesh.getSpatialDimension() == 3); const Element & facet = cohesive_el_to_facet(element.element, third_dimension); if (facet_material.exists(facet.type, facet.ghost_type)) { return facet_material(facet.type, facet.ghost_type)(facet.element); } else { return fallback_value; } } catch (...) { return fallback_value; } } else if (Mesh::getSpatialDimension(element.type) == mesh.getSpatialDimension() - 1) { return facet_material(element.type, element.ghost_type)(element.element); } else { return MaterialSelector::operator()(element); } } /* -------------------------------------------------------------------------- */ MeshDataMaterialCohesiveSelector::MeshDataMaterialCohesiveSelector( const SolidMechanicsModelCohesive & model) : model(model), mesh_facets(model.getMeshFacets()), material_index(mesh_facets.getData<std::string>("physical_names")) { third_dimension = (model.getSpatialDimension() == 3); // backward compatibility v3: to get the former behavior back when the user // creates its own selector this->fallback_selector = std::make_shared<MeshDataMaterialSelector<std::string>>("physical_names", model); } /* -------------------------------------------------------------------------- */ UInt MeshDataMaterialCohesiveSelector::operator()(const Element & element) { if (Mesh::getKind(element.type) == _ek_cohesive) { const auto & facet = mesh_facets.getSubelementToElement( element.type, element.ghost_type)(element.element, third_dimension); try { std::string material_name = this->material_index(facet); return this->model.getMaterialIndex(material_name); } catch (...) { return fallback_value; } } else return MaterialSelector::operator()(element); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ MaterialCohesiveRulesSelector::MaterialCohesiveRulesSelector( const SolidMechanicsModelCohesive & model, const MaterialCohesiveRules & rules, ID mesh_data_id) // what we have here is the name of model and also // the name of different materials : model(model), mesh_data_id(std::move(mesh_data_id)), mesh(model.getMesh()), mesh_facets(model.getMeshFacets()), spatial_dimension(model.getSpatialDimension()), rules(rules) { // cohesive fallback this->fallback_selector = std::make_shared<DefaultMaterialCohesiveSelector>(model); // non cohesive fallback this->fallback_selector->setFallback( std::make_shared<MeshDataMaterialSelector<std::string>>("physical_names", model)); } /* -------------------------------------------------------------------------- */ UInt MaterialCohesiveRulesSelector::operator()(const Element & element) { if (mesh_facets.getSpatialDimension(element.type) == (spatial_dimension - 1)) { const std::vector<Element> & element_to_subelement = mesh_facets.getElementToSubelement(element.type, element.ghost_type)(element.element); // Array<bool> & facets_check = model.getFacetsCheck(); const Element & el1 = element_to_subelement[0]; const Element & el2 = element_to_subelement[1]; ID id1 = mesh.getData<std::string>(mesh_data_id, el1.type, el1.ghost_type)(el1.element); ID id2 = id1; if (el2 != ElementNull) { id2 = mesh.getData<std::string>(mesh_data_id, el2.type, el2.ghost_type)(el2.element); } auto rit = rules.find(std::make_pair(id1, id2)); if (rit == rules.end()) { rit = rules.find(std::make_pair(id2, id1)); } if (rit != rules.end()) { return model.getMaterialIndex(rit->second); } } return MaterialSelector::operator()(element); } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.hh index a5dd25995..a6ef7c4ed 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.hh @@ -1,98 +1,99 @@ /** * @file material_selector_cohesive.hh * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Dec 11 2015 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Mon Dec 18 2017 * * @brief Material selectors for cohesive elements * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "material_selector.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ namespace akantu { class SolidMechanicsModelCohesive; } namespace akantu { #ifndef __AKANTU_MATERIAL_SELECTOR_COHESIVE_HH__ #define __AKANTU_MATERIAL_SELECTOR_COHESIVE_HH__ /* -------------------------------------------------------------------------- */ /** * class that assigns the first cohesive material by default to the * cohesive elements */ class DefaultMaterialCohesiveSelector : public MaterialSelector { public: DefaultMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model); UInt operator()(const Element & element) override; private: const ElementTypeMapArray<UInt> & facet_material; const Mesh & mesh; }; /* -------------------------------------------------------------------------- */ /// To be used with intrinsic elements inserted along mesh physical surfaces class MeshDataMaterialCohesiveSelector : public MaterialSelector { public: MeshDataMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model); UInt operator()(const Element & element) override; protected: const SolidMechanicsModelCohesive & model; const Mesh & mesh_facets; const ElementTypeMapArray<std::string> & material_index; bool third_dimension; }; /// bulk1, bulk2 -> cohesive using MaterialCohesiveRules = std::map<std::pair<ID, ID>, ID>; /* -------------------------------------------------------------------------- */ class MaterialCohesiveRulesSelector : public MaterialSelector { public: MaterialCohesiveRulesSelector(const SolidMechanicsModelCohesive & model, const MaterialCohesiveRules & rules, ID mesh_data_id = "physical_names"); UInt operator()(const Element & element); private: const SolidMechanicsModelCohesive & model; ID mesh_data_id; const Mesh & mesh; const Mesh & mesh_facets; UInt spatial_dimension; MaterialCohesiveRules rules; }; #endif /* __AKANTU_MATERIAL_SELECTOR_COHESIVE_HH__ */ } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field.hh index 22e2c96dd..c67ea80fd 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field.hh @@ -1,68 +1,67 @@ /** * @file cohesive_internal_field.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Oct 08 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Internal field for cohesive elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "internal_field.hh" #ifndef __AKANTU_COHESIVE_INTERNAL_FIELD_HH__ #define __AKANTU_COHESIVE_INTERNAL_FIELD_HH__ namespace akantu { /// internal field class for cohesive materials template <typename T> class CohesiveInternalField : public InternalField<T> { public: CohesiveInternalField(const ID & id, Material & material); ~CohesiveInternalField() override; /// initialize the field to a given number of component void initialize(UInt nb_component) override; private: CohesiveInternalField operator=(__attribute__((unused)) const CohesiveInternalField & other){}; }; /* -------------------------------------------------------------------------- */ /* Facet Internal Field */ /* -------------------------------------------------------------------------- */ template <typename T> class FacetInternalField : public InternalField<T> { public: FacetInternalField(const ID & id, Material & material); ~FacetInternalField() override; /// initialize the field to a given number of component void initialize(UInt nb_component) override; }; } // akantu #endif /* __AKANTU_COHESIVE_INTERNAL_FIELD_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field_tmpl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field_tmpl.hh index 0b2c80de8..52c688752 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field_tmpl.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/cohesive_internal_field_tmpl.hh @@ -1,95 +1,95 @@ /** * @file cohesive_internal_field_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Wed Nov 08 2017 * * @brief implementation of the cohesive internal field * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COHESIVE_INTERNAL_FIELD_TMPL_HH__ #define __AKANTU_COHESIVE_INTERNAL_FIELD_TMPL_HH__ namespace akantu { template <typename T> CohesiveInternalField<T>::CohesiveInternalField(const ID & id, Material & material) : InternalField<T>( id, material, material.getModel().getFEEngine("CohesiveFEEngine"), dynamic_cast<MaterialCohesive &>(material).getElementFilter()) { this->element_kind = _ek_cohesive; } template <typename T> CohesiveInternalField<T>::~CohesiveInternalField() = default; template <typename T> void CohesiveInternalField<T>::initialize(UInt nb_component) { this->internalInitialize(nb_component); } /* -------------------------------------------------------------------------- */ template <typename T> FacetInternalField<T>::FacetInternalField(const ID & id, Material & material) : InternalField<T>( id, material, material.getModel().getFEEngine("FacetsFEEngine"), dynamic_cast<MaterialCohesive &>(material).getFacetFilter()) { this->spatial_dimension -= 1; this->element_kind = _ek_regular; } template <typename T> FacetInternalField<T>::~FacetInternalField() = default; template <typename T> void FacetInternalField<T>::initialize(UInt nb_component) { this->internalInitialize(nb_component); } /* -------------------------------------------------------------------------- */ template <> inline void ParameterTyped<RandomInternalField<Real, FacetInternalField>>::setAuto( const ParserParameter & in_param) { Parameter::setAuto(in_param); RandomParameter<Real> r = in_param; param.setRandomDistribution(r); } /* -------------------------------------------------------------------------- */ template <> inline void ParameterTyped<RandomInternalField<Real, CohesiveInternalField>>::setAuto( const ParserParameter & in_param) { Parameter::setAuto(in_param); RandomParameter<Real> r = in_param; param.setRandomDistribution(r); } } // akantu #endif /* __AKANTU_COHESIVE_INTERNAL_FIELD_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc index 1be65c688..dffd4f680 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc @@ -1,217 +1,216 @@ /** * @file material_cohesive_bilinear.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Feb 22 2012 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Bilinear cohesive constitutive law * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_bilinear.hh" //#include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveBilinear<spatial_dimension>::MaterialCohesiveBilinear( SolidMechanicsModel & model, const ID & id) : MaterialCohesiveLinear<spatial_dimension>(model, id) { AKANTU_DEBUG_IN(); this->registerParam("delta_0", delta_0, Real(0.), _pat_parsable | _pat_readable, "Elastic limit displacement"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); this->sigma_c_eff.setRandomDistribution(this->sigma_c.getRandomParameter()); MaterialCohesiveLinear<spatial_dimension>::initMaterial(); this->delta_max.setDefaultValue(delta_0); this->insertion_stress.setDefaultValue(0); this->delta_max.reset(); this->insertion_stress.reset(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::onElementsAdded( const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); MaterialCohesiveLinear<spatial_dimension>::onElementsAdded(element_list, event); bool scale_traction = false; // don't scale sigma_c if volume_s hasn't been specified by the user if (!Math::are_float_equal(this->volume_s, 0.)) scale_traction = true; Array<Element>::const_scalar_iterator el_it = element_list.begin(); Array<Element>::const_scalar_iterator el_end = element_list.end(); for (; el_it != el_end; ++el_it) { // filter not ghost cohesive elements if (el_it->ghost_type != _not_ghost || Mesh::getKind(el_it->type) != _ek_cohesive) continue; UInt index = el_it->element; ElementType type = el_it->type; UInt nb_element = this->model->getMesh().getNbElement(type); UInt nb_quad_per_element = this->fem_cohesive.getNbIntegrationPoints(type); auto sigma_c_begin = this->sigma_c_eff(type).begin_reinterpret( nb_quad_per_element, nb_element); Vector<Real> sigma_c_vec = sigma_c_begin[index]; auto delta_c_begin = this->delta_c_eff(type).begin_reinterpret( nb_quad_per_element, nb_element); Vector<Real> delta_c_vec = delta_c_begin[index]; if (scale_traction) scaleTraction(*el_it, sigma_c_vec); /** * Recompute sigma_c as * @f$ {\sigma_c}_\textup{new} = * \frac{{\sigma_c}_\textup{old} \delta_c} {\delta_c - \delta_0} @f$ */ for (UInt q = 0; q < nb_quad_per_element; ++q) { delta_c_vec(q) = 2 * this->G_c / sigma_c_vec(q); if (delta_c_vec(q) - delta_0 < Math::getTolerance()) AKANTU_ERROR("delta_0 = " << delta_0 << " must be lower than delta_c = " << delta_c_vec(q) << ", modify your material file"); sigma_c_vec(q) *= delta_c_vec(q) / (delta_c_vec(q) - delta_0); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::scaleTraction( const Element & el, Vector<Real> & sigma_c_vec) { AKANTU_DEBUG_IN(); Real base_sigma_c = this->sigma_c_eff; const Mesh & mesh_facets = this->model->getMeshFacets(); const FEEngine & fe_engine = this->model->getFEEngine(); auto coh_element_to_facet_begin = mesh_facets.getSubelementToElement(el.type).begin(2); const Vector<Element> & coh_element_to_facet = coh_element_to_facet_begin[el.element]; // compute bounding volume Real volume = 0; // loop over facets for (UInt f = 0; f < 2; ++f) { const Element & facet = coh_element_to_facet(f); const Array<std::vector<Element>> & facet_to_element = mesh_facets.getElementToSubelement(facet.type, facet.ghost_type); const std::vector<Element> & element_list = facet_to_element(facet.element); auto elem = element_list.begin(); auto elem_end = element_list.end(); // loop over elements connected to each facet for (; elem != elem_end; ++elem) { // skip cohesive elements and dummy elements if (*elem == ElementNull || Mesh::getKind(elem->type) == _ek_cohesive) continue; // unit vector for integration in order to obtain the volume UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(elem->type); Vector<Real> unit_vector(nb_quadrature_points, 1); volume += fe_engine.integrate(unit_vector, elem->type, elem->element, elem->ghost_type); } } // scale sigma_c sigma_c_vec -= base_sigma_c; sigma_c_vec *= std::pow(this->volume_s / volume, 1. / this->m_s); sigma_c_vec += base_sigma_c; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialCohesiveLinear<spatial_dimension>::computeTraction(normal, el_type, ghost_type); // adjust damage Array<Real>::scalar_iterator delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_max_it = this->delta_max(el_type, ghost_type).begin(); Array<Real>::scalar_iterator damage_it = this->damage(el_type, ghost_type).begin(); Array<Real>::scalar_iterator damage_end = this->damage(el_type, ghost_type).end(); for (; damage_it != damage_end; ++damage_it, ++delta_max_it, ++delta_c_it) { *damage_it = std::max((*delta_max_it - delta_0) / (*delta_c_it - delta_0), Real(0.)); *damage_it = std::min(*damage_it, Real(1.)); } } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_bilinear, MaterialCohesiveBilinear); } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.hh index 4c5b6a09d..5653bf663 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.hh @@ -1,106 +1,105 @@ /** * @file material_cohesive_bilinear.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Sun Dec 03 2017 * * @brief Bilinear cohesive constitutive law * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" #ifndef __AKANTU_MATERIAL_COHESIVE_BILINEAR_HH__ #define __AKANTU_MATERIAL_COHESIVE_BILINEAR_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /** * Cohesive material bilinear * * parameters in the material files : * - delta_0 : elastic limit displacement (default: 0) * - sigma_c : critical stress sigma_c (default: 0) * - beta : weighting parameter for sliding and normal opening (default: * 0) * - G_cI : fracture energy for mode I (default: 0) * - G_cII : fracture energy for mode II (default: 0) * - penalty : stiffness in compression to prevent penetration */ template <UInt spatial_dimension> class MaterialCohesiveBilinear : public MaterialCohesiveLinear<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialCohesiveBilinear(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter void initMaterial() override; /// set material parameters for new elements void onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) override; protected: /// constitutive law void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override; /** * Scale traction sigma_c according to the volume of the * two elements surrounding an element */ void scaleTraction(const Element & el, Vector<Real> & sigma_c_vec); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// elastic limit displacement Real delta_0; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ //#include "material_cohesive_elastic_inline_impl.cc" } // akantu #endif /* __AKANTU_MATERIAL_COHESIVE_BILINEAR_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc index 35ecec09e..139d64a96 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc @@ -1,349 +1,349 @@ /** * @file material_cohesive_exponential.cc * + * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Mon Jul 09 2012 - * @date last modification: Tue Aug 04 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Exponential irreversible cohesive law of mixed mode loading * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_exponential.hh" #include "dof_synchronizer.hh" #include "solid_mechanics_model.hh" #include "sparse_matrix.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveExponential<spatial_dimension>::MaterialCohesiveExponential( SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model, id) { AKANTU_DEBUG_IN(); this->registerParam("beta", beta, Real(0.), _pat_parsable, "Beta parameter"); this->registerParam("exponential_penalty", exp_penalty, true, _pat_parsable, "Is contact penalty following the exponential law?"); this->registerParam( "contact_tangent", contact_tangent, Real(1.0), _pat_parsable, "Ratio of contact tangent over the initial exponential tangent"); // this->initInternalArray(delta_max, 1, _ek_cohesive); use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); if ((exp_penalty) && (contact_tangent != 1)) { contact_tangent = 1; AKANTU_DEBUG_WARNING("The parsed paramter <contact_tangent> is forced to " "1.0 when the contact penalty follows the exponential " "law"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto traction_end = tractions(el_type, ghost_type).end(spatial_dimension); auto delta_max_it = delta_max(el_type, ghost_type).begin(); auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); /// compute scalars Real beta2 = beta * beta; /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++delta_max_it, ++delta_max_prev_it) { /// compute normal and tangential opening vectors Real normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening(spatial_dimension); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; Vector<Real> tangential_opening(spatial_dimension); tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \beta^2 \Delta_t^2 + \Delta_n^2 } @f$ */ Real delta = tangential_opening_norm; delta *= delta * beta2; delta += normal_opening_norm * normal_opening_norm; delta = sqrt(delta); if ((normal_opening_norm < 0) && (std::abs(normal_opening_norm) > Math::getTolerance())) { Vector<Real> op_n(*normal_it); op_n *= normal_opening_norm; Vector<Real> delta_s(*opening_it); delta_s -= op_n; delta = tangential_opening_norm * beta; computeCoupledTraction(*traction_it, *normal_it, delta, delta_s, *delta_max_it, *delta_max_prev_it); computeCompressiveTraction(*traction_it, *normal_it, normal_opening_norm, *opening_it); } else computeCoupledTraction(*traction_it, *normal_it, delta, *opening_it, *delta_max_it, *delta_max_prev_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCoupledTraction( Vector<Real> & tract, const Vector<Real> & normal, Real delta, const Vector<Real> & opening, Real & delta_max_new, Real delta_max) { AKANTU_DEBUG_IN(); /// full damage case if (std::abs(delta) < Math::getTolerance()) { /// set traction to zero tract.clear(); } else { /// element not fully damaged /** * Compute traction loading @f$ \mathbf{T} = * e \sigma_c \frac{\delta}{\delta_c} e^{-\delta/ \delta_c}@f$ */ /** * Compute traction unloading @f$ \mathbf{T} = * \frac{t_{max}}{\delta_{max}} \delta @f$ */ Real beta2 = beta * beta; Real normal_open_norm = opening.dot(normal); Vector<Real> op_n_n(spatial_dimension); op_n_n = normal; op_n_n *= (1 - beta2); op_n_n *= normal_open_norm; tract = beta2 * opening; tract += op_n_n; delta_max_new = std::max(delta_max, delta); tract *= exp(1) * sigma_c * exp(-delta_max_new / delta_c) / delta_c; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCompressiveTraction( Vector<Real> & tract, const Vector<Real> & normal, Real delta_n, __attribute__((unused)) const Vector<Real> & opening) { Vector<Real> temp_tract(normal); if (exp_penalty) { temp_tract *= delta_n * exp(1) * sigma_c * exp(-delta_n / delta_c) / delta_c; } else { Real initial_tg = contact_tangent * exp(1) * sigma_c * delta_n / delta_c; temp_tract *= initial_tg; } tract += temp_tract; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::matrix_iterator tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); auto delta_max_it = delta_max.previous(el_type, ghost_type).begin(); Real beta2 = beta * beta; /** * compute tangent matrix @f$ \frac{\partial \mathbf{t}} * {\partial \delta} = \hat{\mathbf{t}} \otimes * \frac{\partial (t/\delta)}{\partial \delta} * \frac{\hat{\mathbf{t}}}{\delta}+ \frac{t}{\delta} [ \beta^2 \mathbf{I} + * (1-\beta^2) (\mathbf{n} \otimes \mathbf{n})] @f$ **/ /** * In which @f$ * \frac{\partial(t/ \delta)}{\partial \delta} = * \left\{\begin{array} {l l} * -e \frac{\sigma_c}{\delta_c^2 }e^{-\delta / \delta_c} & \quad if * \delta \geq \delta_{max} \\ * 0 & \quad if \delta < \delta_{max}, \delta_n > 0 * \end{array}\right. @f$ **/ for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++delta_max_it) { Real normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening(spatial_dimension); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; Vector<Real> tangential_opening(spatial_dimension); tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); Real delta = tangential_opening_norm; delta *= delta * beta2; delta += normal_opening_norm * normal_opening_norm; delta = sqrt(delta); if ((normal_opening_norm < 0) && (std::abs(normal_opening_norm) > Math::getTolerance())) { Vector<Real> op_n(*normal_it); op_n *= normal_opening_norm; Vector<Real> delta_s(*opening_it); delta_s -= op_n; delta = tangential_opening_norm * beta; computeCoupledTangent(*tangent_it, *normal_it, delta, delta_s, *delta_max_it); computeCompressivePenalty(*tangent_it, *normal_it, normal_opening_norm); } else computeCoupledTangent(*tangent_it, *normal_it, delta, *opening_it, *delta_max_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCoupledTangent( Matrix<Real> & tangent, const Vector<Real> & normal, Real delta, const Vector<Real> & opening, Real) { AKANTU_DEBUG_IN(); Real beta2 = beta * beta; Matrix<Real> J(spatial_dimension, spatial_dimension); J.eye(beta2); if (std::abs(delta) < Math::getTolerance()) { delta = Math::getTolerance(); } Real opening_normal; opening_normal = opening.dot(normal); Vector<Real> delta_e(normal); delta_e *= opening_normal; delta_e *= (1 - beta2); delta_e += (beta2 * opening); Real exponent = exp(1 - delta / delta_c) * sigma_c / delta_c; Matrix<Real> first_term(spatial_dimension, spatial_dimension); first_term.outerProduct(normal, normal); first_term *= (1 - beta2); first_term += J; Matrix<Real> second_term(spatial_dimension, spatial_dimension); second_term.outerProduct(delta_e, delta_e); second_term /= delta; second_term /= delta_c; Matrix<Real> diff(first_term); diff -= second_term; tangent = diff; tangent *= exponent; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCompressivePenalty( Matrix<Real> & tangent, const Vector<Real> & normal, Real delta_n) { if (!exp_penalty) delta_n = 0; Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(normal, normal); Real normal_tg = contact_tangent * exp(1) * sigma_c * exp(-delta_n / delta_c) * (1 - delta_n / delta_c) / delta_c; n_outer_n *= normal_tg; tangent += n_outer_n; } INSTANTIATE_MATERIAL(cohesive_exponential, MaterialCohesiveExponential); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.hh index 3b2b569c0..17e667827 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.hh @@ -1,123 +1,122 @@ /** * @file material_cohesive_exponential.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Feb 06 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Exponential irreversible cohesive law of mixed mode loading * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_EXPONENTIAL_HH__ #define __AKANTU_MATERIAL_COHESIVE_EXPONENTIAL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /** * Cohesive material Exponential damage * * parameters in the material files : * - sigma_c : critical stress sigma_c (default: 0) * - beta : weighting parameter for sliding and normal opening (default: * 0) * - delta_c : critical opening (default: 0) */ template <UInt spatial_dimension> class MaterialCohesiveExponential : public MaterialCohesive { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialCohesiveExponential(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// Initialization void initMaterial() override; /// constitutive law void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the tangent stiffness matrix for an element type void computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type = _not_ghost) override; private: void computeCoupledTraction(Vector<Real> & tract, const Vector<Real> & normal, Real delta, const Vector<Real> & opening, Real & delta_max_new, Real delta_max); void computeCompressiveTraction(Vector<Real> & tract, const Vector<Real> & normal, Real delta_n, const Vector<Real> & opening); void computeCoupledTangent(Matrix<Real> & tangent, const Vector<Real> & normal, Real delta, const Vector<Real> & opening, Real delta_max_new); void computeCompressivePenalty(Matrix<Real> & tangent, const Vector<Real> & normal, Real delta_n); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// beta parameter Real beta; /// contact penalty = initial slope ? bool exp_penalty; /// Ratio of contact tangent over the initial exponential tangent Real contact_tangent; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ // #include "material_cohesive_exponential_inline_impl.cc" } // akantu #endif /* __AKANTU_MATERIAL_COHESIVE_EXPONENTIAL_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc index 806cb7ef9..e63e3154a 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc @@ -1,419 +1,419 @@ /** * @file material_cohesive_linear.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Feb 22 2012 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <algorithm> #include <numeric> /* -------------------------------------------------------------------------- */ #include "dof_synchronizer.hh" #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinear<spatial_dimension>::MaterialCohesiveLinear( SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model, id), sigma_c_eff("sigma_c_eff", *this), delta_c_eff("delta_c_eff", *this), insertion_stress("insertion_stress", *this) { AKANTU_DEBUG_IN(); this->registerParam("beta", beta, Real(0.), _pat_parsable | _pat_readable, "Beta parameter"); this->registerParam("G_c", G_c, Real(0.), _pat_parsable | _pat_readable, "Mode I fracture energy"); this->registerParam("penalty", penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty coefficient"); this->registerParam("volume_s", volume_s, Real(0.), _pat_parsable | _pat_readable, "Reference volume for sigma_c scaling"); this->registerParam("m_s", m_s, Real(1.), _pat_parsable | _pat_readable, "Weibull exponent for sigma_c scaling"); this->registerParam("kappa", kappa, Real(1.), _pat_parsable | _pat_readable, "Kappa parameter"); this->registerParam( "contact_after_breaking", contact_after_breaking, false, _pat_parsable | _pat_readable, "Activation of contact when the elements are fully damaged"); this->registerParam("max_quad_stress_insertion", max_quad_stress_insertion, false, _pat_parsable | _pat_readable, "Insertion of cohesive element when stress is high " "enough just on one quadrature point"); this->registerParam("recompute", recompute, false, _pat_parsable | _pat_modifiable, "recompute solution"); this->use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); sigma_c_eff.initialize(1); delta_c_eff.initialize(1); insertion_stress.initialize(spatial_dimension); if (not Math::are_float_equal(delta_c, 0.)) delta_c_eff.setDefaultValue(delta_c); else delta_c_eff.setDefaultValue(2 * G_c / sigma_c); if (model->getIsExtrinsic()) scaleInsertionTraction(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::updateInternalParameters() { /// compute scalars beta2_kappa2 = beta * beta / kappa / kappa; beta2_kappa = beta * beta / kappa; if (Math::are_float_equal(beta, 0)) beta2_inv = 0; else beta2_inv = 1. / beta / beta; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::scaleInsertionTraction() { AKANTU_DEBUG_IN(); // do nothing if volume_s hasn't been specified by the user if (Math::are_float_equal(volume_s, 0.)) return; const Mesh & mesh_facets = model->getMeshFacets(); const auto & fe_engine = model->getFEEngine(); const auto & fe_engine_facet = model->getFEEngine("FacetsFEEngine"); Real base_sigma_c = sigma_c; for (auto && type_facet : mesh_facets.elementTypes(spatial_dimension - 1)) { const Array<std::vector<Element>> & facet_to_element = mesh_facets.getElementToSubelement(type_facet); UInt nb_facet = facet_to_element.size(); UInt nb_quad_per_facet = fe_engine_facet.getNbIntegrationPoints(type_facet); // iterator to modify sigma_c for all the quadrature points of a facet auto sigma_c_iterator = sigma_c(type_facet).begin_reinterpret(nb_quad_per_facet, nb_facet); for (UInt f = 0; f < nb_facet; ++f, ++sigma_c_iterator) { const std::vector<Element> & element_list = facet_to_element(f); // compute bounding volume Real volume = 0; auto elem = element_list.begin(); auto elem_end = element_list.end(); for (; elem != elem_end; ++elem) { if (*elem == ElementNull) continue; // unit vector for integration in order to obtain the volume UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(elem->type); Vector<Real> unit_vector(nb_quadrature_points, 1); volume += fe_engine.integrate(unit_vector, elem->type, elem->element, elem->ghost_type); } // scale sigma_c *sigma_c_iterator -= base_sigma_c; *sigma_c_iterator *= std::pow(volume_s / volume, 1. / m_s); *sigma_c_iterator += base_sigma_c; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkInsertion( bool check_only) { AKANTU_DEBUG_IN(); const Mesh & mesh_facets = model->getMeshFacets(); CohesiveElementInserter & inserter = model->getElementInserter(); for (auto && type_facet : mesh_facets.elementTypes(spatial_dimension - 1)) { ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); const auto & facets_check = inserter.getCheckFacets(type_facet); auto & f_insertion = inserter.getInsertionFacets(type_facet); auto & f_filter = facet_filter(type_facet); auto & sig_c_eff = sigma_c_eff(type_cohesive); auto & del_c = delta_c_eff(type_cohesive); auto & ins_stress = insertion_stress(type_cohesive); auto & trac_old = tractions.previous(type_cohesive); const auto & f_stress = model->getStressOnFacets(type_facet); const auto & sigma_lim = sigma_c(type_facet); UInt nb_quad_facet = model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); UInt nb_quad_cohesive = model->getFEEngine("CohesiveFEEngine") .getNbIntegrationPoints(type_cohesive); AKANTU_DEBUG_ASSERT(nb_quad_cohesive == nb_quad_facet, "The cohesive element and the corresponding facet do " "not have the same numbers of integration points"); UInt nb_facet = f_filter.size(); // if (nb_facet == 0) continue; auto sigma_lim_it = sigma_lim.begin(); Matrix<Real> stress_tmp(spatial_dimension, spatial_dimension); Matrix<Real> normal_traction(spatial_dimension, nb_quad_facet); Vector<Real> stress_check(nb_quad_facet); UInt sp2 = spatial_dimension * spatial_dimension; const auto & tangents = model->getTangents(type_facet); const auto & normals = model->getFEEngine("FacetsFEEngine") .getNormalsOnIntegrationPoints(type_facet); auto normal_begin = normals.begin(spatial_dimension); auto tangent_begin = tangents.begin(tangents.getNbComponent()); auto facet_stress_begin = f_stress.begin(spatial_dimension, spatial_dimension * 2); std::vector<Real> new_sigmas; std::vector<Vector<Real>> new_normal_traction; std::vector<Real> new_delta_c; // loop over each facet belonging to this material for (UInt f = 0; f < nb_facet; ++f, ++sigma_lim_it) { UInt facet = f_filter(f); // skip facets where check shouldn't be realized if (!facets_check(facet)) continue; // compute the effective norm on each quadrature point of the facet for (UInt q = 0; q < nb_quad_facet; ++q) { UInt current_quad = facet * nb_quad_facet + q; const Vector<Real> & normal = normal_begin[current_quad]; const Vector<Real> & tangent = tangent_begin[current_quad]; const Matrix<Real> & facet_stress_it = facet_stress_begin[current_quad]; // compute average stress on the current quadrature point Matrix<Real> stress_1(facet_stress_it.storage(), spatial_dimension, spatial_dimension); Matrix<Real> stress_2(facet_stress_it.storage() + sp2, spatial_dimension, spatial_dimension); stress_tmp.copy(stress_1); stress_tmp += stress_2; stress_tmp /= 2.; Vector<Real> normal_traction_vec(normal_traction(q)); // compute normal and effective stress stress_check(q) = computeEffectiveNorm(stress_tmp, normal, tangent, normal_traction_vec); } // verify if the effective stress overcomes the threshold Real final_stress = stress_check.mean(); if (max_quad_stress_insertion) final_stress = *std::max_element( stress_check.storage(), stress_check.storage() + nb_quad_facet); if (final_stress > *sigma_lim_it) { f_insertion(facet) = true; if (check_only) continue; // store the new cohesive material parameters for each quadrature // point for (UInt q = 0; q < nb_quad_facet; ++q) { Real new_sigma = stress_check(q); Vector<Real> normal_traction_vec(normal_traction(q)); if (spatial_dimension != 3) normal_traction_vec *= -1.; new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; // set delta_c in function of G_c or a given delta_c value if (Math::are_float_equal(delta_c, 0.)) new_delta = 2 * G_c / new_sigma; else new_delta = (*sigma_lim_it) / new_sigma * delta_c; new_delta_c.push_back(new_delta); } } } // update material data for the new elements UInt old_nb_quad_points = sig_c_eff.size(); UInt new_nb_quad_points = new_sigmas.size(); sig_c_eff.resize(old_nb_quad_points + new_nb_quad_points); ins_stress.resize(old_nb_quad_points + new_nb_quad_points); trac_old.resize(old_nb_quad_points + new_nb_quad_points); del_c.resize(old_nb_quad_points + new_nb_quad_points); for (UInt q = 0; q < new_nb_quad_points; ++q) { sig_c_eff(old_nb_quad_points + q) = new_sigmas[q]; del_c(old_nb_quad_points + q) = new_delta_c[q]; for (UInt dim = 0; dim < spatial_dimension; ++dim) { ins_stress(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); trac_old(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); auto contact_traction_it = contact_tractions(el_type, ghost_type).begin(spatial_dimension); auto contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto traction_end = tractions(el_type, ghost_type).end(spatial_dimension); auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); auto delta_max_it = delta_max(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto damage_it = damage(el_type, ghost_type).begin(); auto insertion_stress_it = insertion_stress(el_type, ghost_type).begin(spatial_dimension); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; this->computeTractionOnQuad( *traction_it, *opening_it, *normal_it, *delta_max_it, *delta_c_it, *insertion_stress_it, *sigma_c_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *contact_traction_it, *contact_opening_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); auto tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); /// NB: delta_max_it points on delta_max_previous, i.e. the /// delta_max related to the solution of the previous incremental /// step auto delta_max_it = delta_max.previous(el_type, ghost_type).begin(); auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto damage_it = damage(el_type, ghost_type).begin(); auto contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; this->computeTangentTractionOnQuad( *tangent_it, *delta_max_it, *delta_c_it, *sigma_c_it, *opening_it, *normal_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *contact_opening_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear, MaterialCohesiveLinear); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh index 56dd8570e..6102277b5 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh @@ -1,188 +1,188 @@ /** * @file material_cohesive_linear.hh * * @author Mauro Corrado <mauro.corrado@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ namespace akantu { /** * Cohesive material linear damage for extrinsic case * * parameters in the material files : * - sigma_c : critical stress sigma_c (default: 0) * - beta : weighting parameter for sliding and normal opening (default: * 0) * - G_cI : fracture energy for mode I (default: 0) * - G_cII : fracture energy for mode II (default: 0) * - penalty : stiffness in compression to prevent penetration */ template <UInt spatial_dimension> class MaterialCohesiveLinear : public MaterialCohesive { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material parameters void initMaterial() override; void updateInternalParameters() override; /// check stress for cohesive elements' insertion void checkInsertion(bool check_only = false) override; /// compute effective stress norm for insertion check Real computeEffectiveNorm(const Matrix<Real> & stress, const Vector<Real> & normal, const Vector<Real> & tangent, Vector<Real> & normal_stress) const; protected: /// constitutive law void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute tangent stiffness matrix void computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) override; /** * Scale insertion traction sigma_c according to the volume of the * two elements surrounding a facet * * see the article: F. Zhou and J. F. Molinari "Dynamic crack * propagation with cohesive elements: a methodology to address mesh * dependency" International Journal for Numerical Methods in * Engineering (2004) */ void scaleInsertionTraction(); /// compute the traction for a given quadrature point inline void computeTractionOnQuad( Vector<Real> & traction, Vector<Real> & opening, const Vector<Real> & normal, Real & delta_max, const Real & delta_c, const Vector<Real> & insertion_stress, const Real & sigma_c, Vector<Real> & normal_opening, Vector<Real> & tangential_opening, Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, bool & penetration, Vector<Real> & contact_traction, Vector<Real> & contact_opening); inline void computeTangentTractionOnQuad( Matrix<Real> & tangent, Real & delta_max, const Real & delta_c, const Real & sigma_c, Vector<Real> & opening, const Vector<Real> & normal, Vector<Real> & normal_opening, Vector<Real> & tangential_opening, Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, bool & penetration, Vector<Real> & contact_opening); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get sigma_c_eff AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(InsertionTraction, sigma_c_eff, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// beta parameter Real beta; /// beta square inverse to compute effective norm Real beta2_inv; /// mode I fracture energy Real G_c; /// kappa parameter Real kappa; /// constitutive law scalar to compute delta Real beta2_kappa2; /// constitutive law scalar to compute traction Real beta2_kappa; /// penalty coefficient Real penalty; /// reference volume used to scale sigma_c Real volume_s; /// weibull exponent used to scale sigma_c Real m_s; /// variable defining if we are recomputing the last loading step /// after load_reduction bool recompute; /// critical effective stress RandomInternalField<Real, CohesiveInternalField> sigma_c_eff; /// effective critical displacement (each element can have a /// different value) CohesiveInternalField<Real> delta_c_eff; /// stress at insertion CohesiveInternalField<Real> insertion_stress; /// variable saying if there should be penalty contact also after /// breaking the cohesive elements bool contact_after_breaking; /// insertion of cohesive element when stress is high enough just on /// one quadrature point bool max_quad_stress_insertion; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ } // akantu #include "material_cohesive_linear_inline_impl.cc" #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc index 432b7e673..0f931e311 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc @@ -1,298 +1,298 @@ /** * @file material_cohesive_linear_fatigue.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Feb 20 2015 - * @date last modification: Tue Jan 12 2016 + * @date last modification: Tue Feb 20 2018 * * @brief See material_cohesive_linear_fatigue.hh for information * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear_fatigue.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinearFatigue<spatial_dimension>::MaterialCohesiveLinearFatigue( SolidMechanicsModel & model, const ID & id) : MaterialCohesiveLinear<spatial_dimension>(model, id), delta_prec("delta_prec", *this), K_plus("K_plus", *this), K_minus("K_minus", *this), T_1d("T_1d", *this), switches("switches", *this), delta_dot_prec("delta_dot_prec", *this), normal_regime("normal_regime", *this) { this->registerParam("delta_f", delta_f, Real(-1.), _pat_parsable | _pat_readable, "delta_f"); this->registerParam("progressive_delta_f", progressive_delta_f, false, _pat_parsable | _pat_readable, "Whether or not delta_f is equal to delta_max"); this->registerParam("count_switches", count_switches, false, _pat_parsable | _pat_readable, "Count the opening/closing switches per element"); this->registerParam( "fatigue_ratio", fatigue_ratio, Real(1.), _pat_parsable | _pat_readable, "What portion of the cohesive law is subjected to fatigue"); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFatigue<spatial_dimension>::initMaterial() { MaterialCohesiveLinear<spatial_dimension>::initMaterial(); // check that delta_f has a proper value or assign a defaul value if (delta_f < 0) delta_f = this->delta_c_eff; else if (delta_f < this->delta_c_eff) AKANTU_ERROR("Delta_f must be greater or equal to delta_c"); delta_prec.initialize(1); K_plus.initialize(1); K_minus.initialize(1); T_1d.initialize(1); normal_regime.initialize(1); if (count_switches) { switches.initialize(1); delta_dot_prec.initialize(1); } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFatigue<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto traction_it = this->tractions(el_type, ghost_type).begin(spatial_dimension); auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); auto contact_traction_it = this->contact_tractions(el_type, ghost_type).begin(spatial_dimension); auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto traction_end = this->tractions(el_type, ghost_type).end(spatial_dimension); const Array<Real> & sigma_c_array = this->sigma_c_eff(el_type, ghost_type); Array<Real> & delta_max_array = this->delta_max(el_type, ghost_type); const Array<Real> & delta_c_array = this->delta_c_eff(el_type, ghost_type); Array<Real> & damage_array = this->damage(el_type, ghost_type); auto insertion_stress_it = this->insertion_stress(el_type, ghost_type).begin(spatial_dimension); Array<Real> & delta_prec_array = delta_prec(el_type, ghost_type); Array<Real> & K_plus_array = K_plus(el_type, ghost_type); Array<Real> & K_minus_array = K_minus(el_type, ghost_type); Array<Real> & T_1d_array = T_1d(el_type, ghost_type); Array<bool> & normal_regime_array = normal_regime(el_type, ghost_type); Array<UInt> * switches_array = nullptr; Array<Real> * delta_dot_prec_array = nullptr; if (count_switches) { switches_array = &switches(el_type, ghost_type); delta_dot_prec_array = &delta_dot_prec(el_type, ghost_type); } auto * memory_space = new Real[2 * spatial_dimension]; Vector<Real> normal_opening(memory_space, spatial_dimension); Vector<Real> tangential_opening(memory_space + spatial_dimension, spatial_dimension); Real tolerance = Math::getTolerance(); /// loop on each quadrature point for (UInt q = 0; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, ++q) { /// compute normal and tangential opening vectors Real normal_opening_norm = opening_it->dot(*normal_it); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \frac{\beta^2}{\kappa^2} \Delta_t^2 + \Delta_n^2 } @f$ */ Real delta = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; bool penetration = normal_opening_norm < -tolerance; if (this->contact_after_breaking == false && Math::are_float_equal(damage_array(q), 1.)) penetration = false; if (penetration) { /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= this->penalty; *contact_opening_it = normal_opening; /// don't consider penetration contribution for delta *opening_it = tangential_opening; normal_opening.clear(); } else { delta += normal_opening_norm * normal_opening_norm; contact_traction_it->clear(); contact_opening_it->clear(); } delta = std::sqrt(delta); /** * Compute traction @f$ \mathbf{T} = \left( * \frac{\beta^2}{\kappa} \Delta_t \mathbf{t} + \Delta_n * \mathbf{n} \right) \frac{\sigma_c}{\delta} \left( 1- * \frac{\delta}{\delta_c} \right)@f$ */ // update maximum displacement and damage delta_max_array(q) = std::max(delta, delta_max_array(q)); damage_array(q) = std::min(delta_max_array(q) / delta_c_array(q), Real(1.)); Real delta_dot = delta - delta_prec_array(q); // count switches if asked if (count_switches) { if ((delta_dot > 0. && (*delta_dot_prec_array)(q) <= 0.) || (delta_dot < 0. && (*delta_dot_prec_array)(q) >= 0.)) ++((*switches_array)(q)); (*delta_dot_prec_array)(q) = delta_dot; } // set delta_f equal to delta_max if desired if (progressive_delta_f) delta_f = delta_max_array(q); // broken element case if (Math::are_float_equal(damage_array(q), 1.)) traction_it->clear(); // just inserted element case else if (Math::are_float_equal(damage_array(q), 0.)) { if (penetration) traction_it->clear(); else *traction_it = *insertion_stress_it; // initialize the 1d traction to sigma_c T_1d_array(q) = sigma_c_array(q); } // normal case else { // if element is closed then there are zero tractions if (delta <= tolerance) traction_it->clear(); // otherwise compute new tractions if the new delta is different // than the previous one else if (std::abs(delta_dot) > tolerance) { // loading case if (delta_dot > 0.) { if (!normal_regime_array(q)) { // equation (4) of the article K_plus_array(q) *= 1. - delta_dot / delta_f; // equivalent to equation (2) of the article T_1d_array(q) += K_plus_array(q) * delta_dot; // in case of reloading, traction must not exceed that of the // envelop of the cohesive law Real max_traction = sigma_c_array(q) * (1 - delta / delta_c_array(q)); bool max_traction_exceeded = T_1d_array(q) > max_traction; if (max_traction_exceeded) T_1d_array(q) = max_traction; // switch to standard linear cohesive law if (delta_max_array(q) > fatigue_ratio * delta_c_array(q)) { // reset delta_max to avoid big jumps in the traction delta_max_array(q) = sigma_c_array(q) / (T_1d_array(q) / delta + sigma_c_array(q) / delta_c_array(q)); damage_array(q) = std::min(delta_max_array(q) / delta_c_array(q), Real(1.)); K_minus_array(q) = sigma_c_array(q) / delta_max_array(q) * (1. - damage_array(q)); normal_regime_array(q) = true; } else { // equation (3) of the article K_minus_array(q) = T_1d_array(q) / delta; // if the traction is following the cohesive envelop, then // K_plus has to be reset if (max_traction_exceeded) K_plus_array(q) = K_minus_array(q); } } else { // compute stiffness according to the standard law K_minus_array(q) = sigma_c_array(q) / delta_max_array(q) * (1. - damage_array(q)); } } // unloading case else if (!normal_regime_array(q)) { // equation (4) of the article K_plus_array(q) += (K_plus_array(q) - K_minus_array(q)) * delta_dot / delta_f; // equivalent to equation (2) of the article T_1d_array(q) = K_minus_array(q) * delta; } // applying the actual stiffness *traction_it = tangential_opening; *traction_it *= this->beta2_kappa; *traction_it += normal_opening; *traction_it *= K_minus_array(q); } } // update precendent delta delta_prec_array(q) = delta; } delete[] memory_space; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear_fatigue, MaterialCohesiveLinearFatigue); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.hh index 93d3329d2..7c204eadc 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.hh @@ -1,133 +1,132 @@ /** * @file material_cohesive_linear_fatigue.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Jun 25 2015 + * @date last modification: Sun Dec 03 2017 * * @brief Linear irreversible cohesive law with dissipative * unloading-reloading cycles * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_FATIGUE_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_FATIGUE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /** * Linear irreversible cohesive law with dissipative * unloading-reloading cycles * * This law uses two different stiffnesses during unloading and * reloading. The implementation is based on the article entitled "A * cohesive model for fatigue crack growth" by Nguyen, Repetto, Ortiz * and Radovitzky (2001). This law is identical to the * MaterialCohesiveLinear one except for the unloading-reloading * phase. * * input parameter: * * - delta_f : it must be greater than delta_c and it is inversely * proportional to the dissipation in the unloading-reloading * cycles (default: delta_c) */ template <UInt spatial_dimension> class MaterialCohesiveLinearFatigue : public MaterialCohesiveLinear<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialCohesiveLinearFatigue(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material parameters void initMaterial() override; protected: /// constitutive law void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the switches AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Switches, switches, UInt); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// delta_f parameter Real delta_f; /// variable saying if delta_f is equal to delta_max for each /// element when the traction is computed bool progressive_delta_f; /// count the opening/closing switches per element bool count_switches; /// delta of the previous step CohesiveInternalField<Real> delta_prec; /// stiffness for reloading CohesiveInternalField<Real> K_plus; /// stiffness for unloading CohesiveInternalField<Real> K_minus; /// 1D traction in the cohesive law CohesiveInternalField<Real> T_1d; /// Number of opening/closing switches CohesiveInternalField<UInt> switches; /// delta increment of the previous time step CohesiveInternalField<Real> delta_dot_prec; /// has the element passed to normal regime (not in fatigue anymore) CohesiveInternalField<bool> normal_regime; /// ratio indicating until what point fatigue is applied in the cohesive law Real fatigue_ratio; }; } // akantu #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_FATIGUE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc index 9de56ad9b..0379b2531 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc @@ -1,277 +1,277 @@ /** * @file material_cohesive_linear_friction.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * * @date creation: Tue Jan 12 2016 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear_friction.hh" #include "solid_mechanics_model_cohesive.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinearFriction<spatial_dimension>:: MaterialCohesiveLinearFriction(SolidMechanicsModel & model, const ID & id) : MaterialParent(model, id), residual_sliding("residual_sliding", *this), friction_force("friction_force", *this) { AKANTU_DEBUG_IN(); this->registerParam("mu", mu_max, Real(0.), _pat_parsable | _pat_readable, "Maximum value of the friction coefficient"); this->registerParam("penalty_for_friction", friction_penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty parameter for the friction behavior"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFriction<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialParent::initMaterial(); friction_force.initialize(spatial_dimension); residual_sliding.initialize(1); residual_sliding.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFriction<spatial_dimension>::computeTraction( __attribute__((unused)) const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); residual_sliding.resize(); friction_force.resize(); /// define iterators auto traction_it = this->tractions(el_type, ghost_type).begin(spatial_dimension); auto traction_end = this->tractions(el_type, ghost_type).end(spatial_dimension); auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); auto previous_opening_it = this->opening.previous(el_type, ghost_type).begin(spatial_dimension); auto contact_traction_it = this->contact_tractions(el_type, ghost_type).begin(spatial_dimension); auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = this->normal.begin(spatial_dimension); auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); auto delta_max_it = this->delta_max(el_type, ghost_type).begin(); auto delta_max_prev_it = this->delta_max.previous(el_type, ghost_type).begin(); auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); auto damage_it = this->damage(el_type, ghost_type).begin(); auto insertion_stress_it = this->insertion_stress(el_type, ghost_type).begin(spatial_dimension); auto res_sliding_it = this->residual_sliding(el_type, ghost_type).begin(); auto res_sliding_prev_it = this->residual_sliding.previous(el_type, ghost_type).begin(); auto friction_force_it = this->friction_force(el_type, ghost_type).begin(spatial_dimension); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); if (not this->model->isDefaultSolverExplicit()) this->delta_max(el_type, ghost_type) .copy(this->delta_max.previous(el_type, ghost_type)); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, ++delta_max_prev_it, ++res_sliding_it, ++res_sliding_prev_it, ++friction_force_it, ++previous_opening_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; this->computeTractionOnQuad( *traction_it, *opening_it, *normal_it, *delta_max_it, *delta_c_it, *insertion_stress_it, *sigma_c_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *contact_traction_it, *contact_opening_it); if (penetration) { /// the friction coefficient mu increases with the damage. It /// equals the maximum value when damage = 1. // Real damage = std::min(*delta_max_prev_it / *delta_c_it, // Real(1.)); Real mu = mu_max; // * damage; /// the definition of tau_max refers to the opening /// (penetration) of the previous incremental step Real normal_opening_prev_norm = std::min(previous_opening_it->dot(*normal_it), Real(0.)); // Vector<Real> normal_opening_prev = (*normal_it); // normal_opening_prev *= normal_opening_prev_norm; Real tau_max = mu * this->penalty * (std::abs(normal_opening_prev_norm)); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); /// tau is the norm of the friction force, acting tangentially to the /// surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if ((tangential_opening_norm - *res_sliding_prev_it) < 0.0) tau = -tau; /// from tau get the x and y components of friction, to be added in the /// force vector Vector<Real> tangent_unit_vector(spatial_dimension); tangent_unit_vector = tangential_opening / tangential_opening_norm; *friction_force_it = tau * tangent_unit_vector; /// update residual_sliding *res_sliding_it = tangential_opening_norm - (std::abs(tau) / friction_penalty); } else { friction_force_it->clear(); } *traction_it += *friction_force_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFriction<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, __attribute__((unused)) const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); auto tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); auto normal_it = this->normal.begin(spatial_dimension); auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); auto previous_opening_it = this->opening.previous(el_type, ghost_type).begin(spatial_dimension); /** * NB: delta_max_it points on delta_max_previous, i.e. the * delta_max related to the solution of the previous incremental * step */ auto delta_max_it = this->delta_max.previous(el_type, ghost_type).begin(); auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); auto damage_it = this->damage(el_type, ghost_type).begin(); auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); auto res_sliding_prev_it = this->residual_sliding.previous(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++previous_opening_it, ++delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it, ++res_sliding_prev_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; this->computeTangentTractionOnQuad( *tangent_it, *delta_max_it, *delta_c_it, *sigma_c_it, *opening_it, *normal_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *contact_opening_it); if (penetration) { // Real damage = std::min(*delta_max_it / *delta_c_it, Real(1.)); Real mu = mu_max; // * damage; Real normal_opening_prev_norm = std::min(previous_opening_it->dot(*normal_it), Real(0.)); // Vector<Real> normal_opening_prev = (*normal_it); // normal_opening_prev *= normal_opening_prev_norm; Real tau_max = mu * this->penalty * (std::abs(normal_opening_prev_norm)); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); // tau is the norm of the friction force, acting tangentially to the // surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if (tau < tau_max && tau_max > Math::getTolerance()) { Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(1.); Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); Matrix<Real> nn(n_outer_n); I -= nn; *tangent_it += I * friction_penalty; } } // check if the tangential stiffness matrix is symmetric // for (UInt h = 0; h < spatial_dimension; ++h){ // for (UInt l = h; l < spatial_dimension; ++l){ // if (l > h){ // Real k_ls = (*tangent_it)[spatial_dimension*h+l]; // Real k_us = (*tangent_it)[spatial_dimension*l+h]; // // std::cout << "k_ls = " << k_ls << std::endl; // // std::cout << "k_us = " << k_us << std::endl; // if (std::abs(k_ls) > 1e-13 && std::abs(k_us) > 1e-13){ // Real error = std::abs((k_ls - k_us) / k_us); // if (error > 1e-10){ // std::cout << "non symmetric cohesive matrix" << std::endl; // // std::cout << "error " << error << std::endl; // } // } // } // } // } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear_friction, MaterialCohesiveLinearFriction); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.hh index f928863f1..8df782f9c 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.hh @@ -1,106 +1,105 @@ /** * @file material_cohesive_linear_friction.hh * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jan 12 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_FRICTION_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_FRICTION_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /** * Cohesive material linear with friction force * * parameters in the material files : * - mu : friction coefficient * - penalty_for_friction : Penalty parameter for the friction behavior */ template <UInt spatial_dimension> class MaterialCohesiveLinearFriction : public MaterialCohesiveLinear<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ using MaterialParent = MaterialCohesiveLinear<spatial_dimension>; public: MaterialCohesiveLinearFriction(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material parameters void initMaterial() override; protected: /// constitutive law void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute tangent stiffness matrix void computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// maximum value of the friction coefficient Real mu_max; /// penalty parameter for the friction law Real friction_penalty; /// history parameter for the friction law CohesiveInternalField<Real> residual_sliding; /// friction force CohesiveInternalField<Real> friction_force; }; } // akantu #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_FRICTION_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc index 08322ed07..448c63ea2 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc @@ -1,264 +1,266 @@ /** * @file material_cohesive_linear_inline_impl.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Apr 22 2015 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Inline functions of the MaterialCohesiveLinear * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_INLINE_IMPL_CC__ /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim> inline Real MaterialCohesiveLinear<dim>::computeEffectiveNorm( const Matrix<Real> & stress, const Vector<Real> & normal, const Vector<Real> & tangent, Vector<Real> & normal_traction) const { normal_traction.mul<false>(stress, normal); Real normal_contrib = normal_traction.dot(normal); /// in 3D tangential components must be summed Real tangent_contrib = 0; if (dim == 2) { Real tangent_contrib_tmp = normal_traction.dot(tangent); tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; } else if (dim == 3) { for (UInt s = 0; s < dim - 1; ++s) { const Vector<Real> tangent_v(tangent.storage() + s * dim, dim); Real tangent_contrib_tmp = normal_traction.dot(tangent_v); tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; } } tangent_contrib = std::sqrt(tangent_contrib); normal_contrib = std::max(Real(0.), normal_contrib); return std::sqrt(normal_contrib * normal_contrib + tangent_contrib * tangent_contrib * beta2_inv); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialCohesiveLinear<dim>::computeTractionOnQuad( Vector<Real> & traction, Vector<Real> & opening, const Vector<Real> & normal, Real & delta_max, const Real & delta_c, const Vector<Real> & insertion_stress, const Real & sigma_c, Vector<Real> & normal_opening, Vector<Real> & tangential_opening, Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, bool & penetration, Vector<Real> & contact_traction, Vector<Real> & contact_opening) { /// compute normal and tangential opening vectors normal_opening_norm = opening.dot(normal); normal_opening = normal; normal_opening *= normal_opening_norm; tangential_opening = opening; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \frac{\beta^2}{\kappa^2} \Delta_t^2 + \Delta_n^2 } @f$ */ Real delta = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm / delta_c < -Math::getTolerance(); // penetration = normal_opening_norm < 0.; if (this->contact_after_breaking == false && Math::are_float_equal(damage, 1.)) penetration = false; if (penetration) { /// use penalty coefficient in case of penetration contact_traction = normal_opening; contact_traction *= this->penalty; contact_opening = normal_opening; /// don't consider penetration contribution for delta opening = tangential_opening; normal_opening.clear(); } else { delta += normal_opening_norm * normal_opening_norm; contact_traction.clear(); contact_opening.clear(); } delta = std::sqrt(delta); /// update maximum displacement and damage delta_max = std::max(delta_max, delta); damage = std::min(delta_max / delta_c, Real(1.)); /** * Compute traction @f$ \mathbf{T} = \left( * \frac{\beta^2}{\kappa} \Delta_t \mathbf{t} + \Delta_n * \mathbf{n} \right) \frac{\sigma_c}{\delta} \left( 1- * \frac{\delta}{\delta_c} \right)@f$ */ if (Math::are_float_equal(damage, 1.)) traction.clear(); else if (Math::are_float_equal(damage, 0.)) { if (penetration) traction.clear(); else traction = insertion_stress; } else { traction = tangential_opening; traction *= this->beta2_kappa; traction += normal_opening; AKANTU_DEBUG_ASSERT(delta_max != 0., "Division by zero, tolerance might be too low"); traction *= sigma_c / delta_max * (1. - damage); } } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void MaterialCohesiveLinear<dim>::computeTangentTractionOnQuad( Matrix<Real> & tangent, Real & delta_max, const Real & delta_c, const Real & sigma_c, Vector<Real> & opening, const Vector<Real> & normal, Vector<Real> & normal_opening, Vector<Real> & tangential_opening, Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, bool & penetration, Vector<Real> & contact_opening) { /** * During the update of the residual the interpenetrations are * stored in the array "contact_opening", therefore, in the case * of penetration, in the array "opening" there are only the * tangential components. */ opening += contact_opening; /// compute normal and tangential opening vectors normal_opening_norm = opening.dot(normal); normal_opening = normal; normal_opening *= normal_opening_norm; tangential_opening = opening; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); Real delta = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm < 0.0; if (this->contact_after_breaking == false && Math::are_float_equal(damage, 1.)) penetration = false; Real derivative = 0; // derivative = d(t/delta)/ddelta Real t = 0; Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(normal, normal); if (penetration) { /// stiffness in compression given by the penalty parameter tangent += n_outer_n; tangent *= penalty; opening = tangential_opening; normal_opening_norm = opening.dot(normal); normal_opening = normal; normal_opening *= normal_opening_norm; } else { delta += normal_opening_norm * normal_opening_norm; } delta = std::sqrt(delta); /** * Delta has to be different from 0 to have finite values of * tangential stiffness. At the element insertion, delta = * 0. Therefore, a fictictious value is defined, for the * evaluation of the first value of K. */ if (delta < Math::getTolerance()) delta = delta_c / 1000.; if (delta >= delta_max) { if (delta <= delta_c) { derivative = -sigma_c / (delta * delta); t = sigma_c * (1 - delta / delta_c); } else { derivative = 0.; t = 0.; } } else if (delta < delta_max) { Real tmax = sigma_c * (1 - delta_max / delta_c); t = tmax / delta_max * delta; } /// computation of the derivative of the constitutive law (dT/ddelta) Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(this->beta2_kappa); Matrix<Real> nn(n_outer_n); nn *= (1. - this->beta2_kappa); nn += I; nn *= t / delta; Vector<Real> t_tilde(normal_opening); t_tilde *= (1. - this->beta2_kappa2); Vector<Real> mm(opening); mm *= this->beta2_kappa2; t_tilde += mm; Vector<Real> t_hat(normal_opening); t_hat += this->beta2_kappa * tangential_opening; Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(t_hat, t_tilde); prov *= derivative / delta; prov += nn; Matrix<Real> prov_t = prov.transpose(); tangent += prov_t; } /* -------------------------------------------------------------------------- */ } // akantu /* -------------------------------------------------------------------------- */ #endif //__AKANTU_MATERIAL_COHESIVE_LINEAR_INLINE_IMPL_CC__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc index f31411171..622b5e77b 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc @@ -1,414 +1,413 @@ /** * @file material_cohesive_linear_uncoupled.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * - * @date creation: Wed Feb 22 2012 - * @date last modification: Thu Jan 14 2016 + * @date creation: Mon Jul 25 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @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) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <algorithm> #include <numeric> /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear_uncoupled.hh" #include "solid_mechanics_model_cohesive.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinearUncoupled<spatial_dimension>:: MaterialCohesiveLinearUncoupled(SolidMechanicsModel & model, const ID & id) : MaterialCohesiveLinear<spatial_dimension>(model, id), delta_n_max("delta_n_max", *this), delta_t_max("delta_t_max", *this), damage_n("damage_n", *this), damage_t("damage_t", *this) { AKANTU_DEBUG_IN(); this->registerParam( "roughness", R, Real(1.), _pat_parsable | _pat_readable, "Roughness to define coupling between mode II and mode I"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearUncoupled<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesiveLinear<spatial_dimension>::initMaterial(); delta_n_max.initialize(1); delta_t_max.initialize(1); damage_n.initialize(1); damage_t.initialize(1); delta_n_max.initializeHistory(); delta_t_max.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearUncoupled<spatial_dimension>::computeTraction( const Array<Real> &, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); delta_n_max.resize(); delta_t_max.resize(); damage_n.resize(); damage_t.resize(); /// define iterators auto traction_it = this->tractions(el_type, ghost_type).begin(spatial_dimension); auto traction_end = this->tractions(el_type, ghost_type).end(spatial_dimension); auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); auto contact_traction_it = this->contact_tractions(el_type, ghost_type).begin(spatial_dimension); auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = this->normal.begin(spatial_dimension); auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); auto delta_n_max_it = delta_n_max(el_type, ghost_type).begin(); auto delta_t_max_it = delta_t_max(el_type, ghost_type).begin(); auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); auto damage_n_it = damage_n(el_type, ghost_type).begin(); auto damage_t_it = damage_t(el_type, ghost_type).begin(); auto insertion_stress_it = this->insertion_stress(el_type, ghost_type).begin(spatial_dimension); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++contact_traction_it, ++contact_opening_it, ++normal_it, ++sigma_c_it, ++delta_n_max_it, ++delta_t_max_it, ++delta_c_it, ++damage_n_it, ++damage_t_it, ++insertion_stress_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real delta_c2_R2 = *delta_c_it * (*delta_c_it) / R / R; /// compute normal and tangential opening vectors normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening = *normal_it; normal_opening *= normal_opening_norm; // std::cout<< "normal_opening_norm = " << normal_opening_norm // <<std::endl; Vector<Real> tangential_opening = *opening_it; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); /// compute effective opening displacement Real delta_n = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; Real delta_t = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm < 0.0; if (this->contact_after_breaking == false && Math::are_float_equal(*damage_n_it, 1.)) penetration = false; if (penetration) { /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= this->penalty; *contact_opening_it = normal_opening; /// don't consider penetration contribution for delta //*opening_it = tangential_opening; normal_opening.clear(); } else { delta_n += normal_opening_norm * normal_opening_norm; delta_t += normal_opening_norm * normal_opening_norm * delta_c2_R2; contact_traction_it->clear(); contact_opening_it->clear(); } delta_n = std::sqrt(delta_n); delta_t = std::sqrt(delta_t); /// update maximum displacement and damage *delta_n_max_it = std::max(*delta_n_max_it, delta_n); *damage_n_it = std::min(*delta_n_max_it / *delta_c_it, Real(1.)); *delta_t_max_it = std::max(*delta_t_max_it, delta_t); *damage_t_it = std::min(*delta_t_max_it / *delta_c_it, Real(1.)); Vector<Real> normal_traction(spatial_dimension); Vector<Real> shear_traction(spatial_dimension); /// NORMAL TRACTIONS if (Math::are_float_equal(*damage_n_it, 1.)) normal_traction.clear(); else if (Math::are_float_equal(*damage_n_it, 0.)) { if (penetration) normal_traction.clear(); else normal_traction = *insertion_stress_it; } else { // the following formulation holds both in loading and in // unloading-reloading normal_traction = normal_opening; AKANTU_DEBUG_ASSERT(*delta_n_max_it != 0., "Division by zero, tolerance might be too low"); normal_traction *= *sigma_c_it / (*delta_n_max_it) * (1. - *damage_n_it); } /// SHEAR TRACTIONS if (Math::are_float_equal(*damage_t_it, 1.)) shear_traction.clear(); else if (Math::are_float_equal(*damage_t_it, 0.)) { shear_traction.clear(); } else { shear_traction = tangential_opening; AKANTU_DEBUG_ASSERT(*delta_t_max_it != 0., "Division by zero, tolerance might be too low"); shear_traction *= this->beta2_kappa; shear_traction *= *sigma_c_it / (*delta_t_max_it) * (1. - *damage_t_it); } *traction_it = normal_traction; *traction_it += shear_traction; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearUncoupled<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> &, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); auto tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); auto normal_it = this->normal.begin(spatial_dimension); auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); /// NB: delta_max_it points on delta_max_previous, i.e. the /// delta_max related to the solution of the previous incremental /// step auto delta_n_max_it = delta_n_max.previous(el_type, ghost_type).begin(); auto delta_t_max_it = delta_t_max.previous(el_type, ghost_type).begin(); auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); auto damage_n_it = damage_n(el_type, ghost_type).begin(); auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++sigma_c_it, ++delta_c_it, ++delta_n_max_it, ++delta_t_max_it, ++damage_n_it, ++contact_opening_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real delta_c2_R2 = *delta_c_it * (*delta_c_it) / R / R; /** * During the update of the residual the interpenetrations are * stored in the array "contact_opening", therefore, in the case * of penetration, in the array "opening" there are only the * tangential components. */ *opening_it += *contact_opening_it; /// compute normal and tangential opening vectors normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening = *normal_it; normal_opening *= normal_opening_norm; Vector<Real> tangential_opening = *opening_it; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); Real delta_n = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; Real delta_t = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm < 0.0; if (this->contact_after_breaking == false && Math::are_float_equal(*damage_n_it, 1.)) penetration = false; Real derivative = 0; // derivative = d(t/delta)/ddelta Real T = 0; /// TANGENT STIFFNESS FOR NORMAL TRACTIONS Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); if (penetration) { /// stiffness in compression given by the penalty parameter *tangent_it = n_outer_n; *tangent_it *= this->penalty; //*opening_it = tangential_opening; normal_opening.clear(); } else { delta_n += normal_opening_norm * normal_opening_norm; delta_n = std::sqrt(delta_n); delta_t += normal_opening_norm * normal_opening_norm * delta_c2_R2; /** * Delta has to be different from 0 to have finite values of * tangential stiffness. At the element insertion, delta = * 0. Therefore, a fictictious value is defined, for the * evaluation of the first value of K. */ if (delta_n < Math::getTolerance()) delta_n = *delta_c_it / 1000.; // loading if (delta_n >= *delta_n_max_it) { if (delta_n <= *delta_c_it) { derivative = -(*sigma_c_it) / (delta_n * delta_n); T = *sigma_c_it * (1 - delta_n / *delta_c_it); } else { derivative = 0.; T = 0.; } // unloading-reloading } else if (delta_n < *delta_n_max_it) { Real T_max = *sigma_c_it * (1 - *delta_n_max_it / *delta_c_it); derivative = 0.; T = T_max / *delta_n_max_it * delta_n; } /// computation of the derivative of the constitutive law (dT/ddelta) Matrix<Real> nn(n_outer_n); nn *= T / delta_n; Vector<Real> Delta_tilde(normal_opening); Delta_tilde *= (1. - this->beta2_kappa2); Vector<Real> mm(*opening_it); mm *= this->beta2_kappa2; Delta_tilde += mm; const Vector<Real> & Delta_hat(normal_opening); Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(Delta_hat, Delta_tilde); prov *= derivative / delta_n; prov += nn; Matrix<Real> prov_t = prov.transpose(); *tangent_it = prov_t; } derivative = 0.; T = 0.; /// TANGENT STIFFNESS FOR SHEAR TRACTIONS delta_t = std::sqrt(delta_t); /** * Delta has to be different from 0 to have finite values of * tangential stiffness. At the element insertion, delta = * 0. Therefore, a fictictious value is defined, for the * evaluation of the first value of K. */ if (delta_t < Math::getTolerance()) delta_t = *delta_c_it / 1000.; // loading if (delta_t >= *delta_t_max_it) { if (delta_t <= *delta_c_it) { derivative = -(*sigma_c_it) / (delta_t * delta_t); T = *sigma_c_it * (1 - delta_t / *delta_c_it); } else { derivative = 0.; T = 0.; } // unloading-reloading } else if (delta_t < *delta_t_max_it) { Real T_max = *sigma_c_it * (1 - *delta_t_max_it / *delta_c_it); derivative = 0.; T = T_max / *delta_t_max_it * delta_t; } /// computation of the derivative of the constitutive law (dT/ddelta) Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(); Matrix<Real> nn(n_outer_n); I -= nn; I *= T / delta_t; Vector<Real> Delta_tilde(normal_opening); Delta_tilde *= (delta_c2_R2 - this->beta2_kappa2); Vector<Real> mm(*opening_it); mm *= this->beta2_kappa2; Delta_tilde += mm; Vector<Real> Delta_hat(tangential_opening); Delta_hat *= this->beta2_kappa; Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(Delta_hat, Delta_tilde); prov *= derivative / delta_t; prov += I; Matrix<Real> prov_t = prov.transpose(); *tangent_it += prov_t; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear_uncoupled, MaterialCohesiveLinearUncoupled); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.hh index f63de86de..4a7d61404 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.hh @@ -1,103 +1,102 @@ /** - * @file material_cohesive_linear.hh + * @file material_cohesive_linear_uncoupled.hh * * @author Mauro Corrado <mauro.corrado@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_UNCOUPLED_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_UNCOUPLED_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /** * Cohesive material linear with two different laws for mode I and * mode II, for extrinsic case * * parameters in the material files : * - roughness : define the interaction between mode I and mode II (default: 0) */ template <UInt spatial_dimension> class MaterialCohesiveLinearUncoupled : public MaterialCohesiveLinear<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ // typedef MaterialCohesiveLinear<spatial_dimension> MaterialParent; public: MaterialCohesiveLinearUncoupled(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material parameters void initMaterial() override; protected: /// constitutive law void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute tangent stiffness matrix void computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// parameter to tune the interaction between mode II and mode I Real R; /// maximum normal displacement CohesiveInternalField<Real> delta_n_max; /// maximum tangential displacement CohesiveInternalField<Real> delta_t_max; /// damage associated to normal tractions CohesiveInternalField<Real> damage_n; /// damage associated to shear tractions CohesiveInternalField<Real> damage_t; }; } // akantu #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_UNCOUPLED_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc index 4d55b04ce..e22a4f934 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc @@ -1,573 +1,574 @@ /** * @file material_cohesive.cc * + * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Feb 22 2012 - * @date last modification: Tue Jan 12 2016 + * @date last modification: Mon Feb 19 2018 * * @brief Specialization of the material class for cohesive elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" #include "aka_random_generator.hh" #include "dof_synchronizer.hh" #include "fe_engine_template.hh" #include "integrator_gauss.hh" #include "shape_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MaterialCohesive::MaterialCohesive(SolidMechanicsModel & model, const ID & id) : Material(model, id), facet_filter("facet_filter", id, this->getMemoryID()), fem_cohesive( model.getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine")), reversible_energy("reversible_energy", *this), total_energy("total_energy", *this), opening("opening", *this), tractions("tractions", *this), contact_tractions("contact_tractions", *this), contact_opening("contact_opening", *this), delta_max("delta max", *this), use_previous_delta_max(false), use_previous_opening(false), damage("damage", *this), sigma_c("sigma_c", *this), normal(0, spatial_dimension, "normal") { AKANTU_DEBUG_IN(); this->model = dynamic_cast<SolidMechanicsModelCohesive *>(&model); this->registerParam("sigma_c", sigma_c, _pat_parsable | _pat_readable, "Critical stress"); this->registerParam("delta_c", delta_c, Real(0.), _pat_parsable | _pat_readable, "Critical displacement"); this->element_filter.initialize(this->model->getMesh(), _spatial_dimension = spatial_dimension, _element_kind = _ek_cohesive); // this->model->getMesh().initElementTypeMapArray( // this->element_filter, 1, spatial_dimension, false, _ek_cohesive); if (this->model->getIsExtrinsic()) this->facet_filter.initialize(this->model->getMeshFacets(), _spatial_dimension = spatial_dimension - 1, _element_kind = _ek_regular); // this->model->getMeshFacets().initElementTypeMapArray(facet_filter, 1, // spatial_dimension - // 1); this->reversible_energy.initialize(1); this->total_energy.initialize(1); this->tractions.initialize(spatial_dimension); this->tractions.initializeHistory(); this->contact_tractions.initialize(spatial_dimension); this->contact_opening.initialize(spatial_dimension); this->opening.initialize(spatial_dimension); this->opening.initializeHistory(); this->delta_max.initialize(1); this->damage.initialize(1); if (this->model->getIsExtrinsic()) this->sigma_c.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MaterialCohesive::~MaterialCohesive() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); if (this->use_previous_delta_max) this->delta_max.initializeHistory(); if (this->use_previous_opening) this->opening.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Tractions", tractions); #endif auto & internal_force = const_cast<Array<Real> &>(model->getInternalForce()); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { auto & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; const auto & shapes = fem_cohesive.getShapes(type, ghost_type); auto & traction = tractions(type, ghost_type); auto & contact_traction = contact_tractions(type, ghost_type); UInt size_of_shapes = shapes.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem_cohesive.getNbIntegrationPoints(type, ghost_type); /// compute @f$t_i N_a@f$ Array<Real> * traction_cpy = new Array<Real>( nb_element * nb_quadrature_points, spatial_dimension * size_of_shapes); auto traction_it = traction.begin(spatial_dimension, 1); auto contact_traction_it = contact_traction.begin(spatial_dimension, 1); auto shapes_filtered_begin = shapes.begin(1, size_of_shapes); auto traction_cpy_it = traction_cpy->begin(spatial_dimension, size_of_shapes); Matrix<Real> traction_tmp(spatial_dimension, 1); for (UInt el = 0; el < nb_element; ++el) { UInt current_quad = elem_filter(el) * nb_quadrature_points; for (UInt q = 0; q < nb_quadrature_points; ++q, ++traction_it, ++contact_traction_it, ++current_quad, ++traction_cpy_it) { const Matrix<Real> & shapes_filtered = shapes_filtered_begin[current_quad]; traction_tmp.copy(*traction_it); traction_tmp += *contact_traction_it; traction_cpy_it->mul<false, false>(traction_tmp, shapes_filtered); } } /** * compute @f$\int t \cdot N\, dS@f$ by @f$ \sum_q \mathbf{N}^t * \mathbf{t}_q \overline w_q J_q@f$ */ Array<Real> * int_t_N = new Array<Real>( nb_element, spatial_dimension * size_of_shapes, "int_t_N"); fem_cohesive.integrate(*traction_cpy, *int_t_N, spatial_dimension * size_of_shapes, type, ghost_type, elem_filter); delete traction_cpy; int_t_N->extendComponentsInterlaced(2, int_t_N->getNbComponent()); Real * int_t_N_val = int_t_N->storage(); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < size_of_shapes * spatial_dimension; ++n) int_t_N_val[n] *= -1.; int_t_N_val += nb_nodes_per_element * spatial_dimension; } /// assemble model->getDOFManager().assembleElementalArrayLocalArray( *int_t_N, internal_force, type, ghost_type, -1, elem_filter); delete int_t_N; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { UInt nb_quadrature_points = fem_cohesive.getNbIntegrationPoints(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<Real> & shapes = fem_cohesive.getShapes(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (!nb_element) continue; UInt size_of_shapes = shapes.getNbComponent(); Array<Real> * shapes_filtered = new Array<Real>( nb_element * nb_quadrature_points, size_of_shapes, "filtered shapes"); Real * shapes_filtered_val = shapes_filtered->storage(); UInt * elem_filter_val = elem_filter.storage(); for (UInt el = 0; el < nb_element; ++el) { auto shapes_val = shapes.storage() + elem_filter_val[el] * size_of_shapes * nb_quadrature_points; memcpy(shapes_filtered_val, shapes_val, size_of_shapes * nb_quadrature_points * sizeof(Real)); shapes_filtered_val += size_of_shapes * nb_quadrature_points; } /** * compute A matrix @f$ \mathbf{A} = \left[\begin{array}{c c c c c c c c c c *c c} * 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 \\ * 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 \\ * 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 \\ * 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 \\ * 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 \\ * 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 * \end{array} \right]@f$ **/ // UInt size_of_A = // spatial_dimension*size_of_shapes*spatial_dimension*nb_nodes_per_element; // Real * A = new Real[size_of_A]; // memset(A, 0, size_of_A*sizeof(Real)); Matrix<Real> A(spatial_dimension * size_of_shapes, spatial_dimension * nb_nodes_per_element); for (UInt i = 0; i < spatial_dimension * size_of_shapes; ++i) { A(i, i) = 1; A(i, i + spatial_dimension * size_of_shapes) = -1; } // compute traction. This call is not necessary for the linear // cohesive law that, currently, is the only one used for the // extrinsic approach. // if (!model->getIsExtrinsic()){ // computeTraction(ghost_type); //} /// get the tangent matrix @f$\frac{\partial{(t/\delta)}}{\partial{\delta}} /// @f$ Array<Real> * tangent_stiffness_matrix = new Array<Real>( nb_element * nb_quadrature_points, spatial_dimension * spatial_dimension, "tangent_stiffness_matrix"); // Array<Real> * normal = new Array<Real>(nb_element * // nb_quadrature_points, spatial_dimension, "normal"); normal.resize(nb_quadrature_points); computeNormal(model->getCurrentPosition(), normal, type, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ // computeOpening(model->getDisplacement(), opening(type, ghost_type), type, // ghost_type); tangent_stiffness_matrix->clear(); computeTangentTraction(type, *tangent_stiffness_matrix, normal, ghost_type); // delete normal; UInt size_at_nt_d_n_a = spatial_dimension * nb_nodes_per_element * spatial_dimension * nb_nodes_per_element; Array<Real> * at_nt_d_n_a = new Array<Real>( nb_element * nb_quadrature_points, size_at_nt_d_n_a, "A^t*N^t*D*N*A"); Array<Real>::iterator<Vector<Real>> shapes_filt_it = shapes_filtered->begin(size_of_shapes); Array<Real>::matrix_iterator D_it = tangent_stiffness_matrix->begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator At_Nt_D_N_A_it = at_nt_d_n_a->begin(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Array<Real>::matrix_iterator At_Nt_D_N_A_end = at_nt_d_n_a->end(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Matrix<Real> N(spatial_dimension, spatial_dimension * size_of_shapes); Matrix<Real> N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); Matrix<Real> D_N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); for (; At_Nt_D_N_A_it != At_Nt_D_N_A_end; ++At_Nt_D_N_A_it, ++D_it, ++shapes_filt_it) { N.clear(); /** * store the shapes in voigt notations matrix @f$\mathbf{N} = * \begin{array}{cccccc} N_0(\xi) & 0 & N_1(\xi) &0 & N_2(\xi) & 0 \\ * 0 & * N_0(\xi)& 0 &N_1(\xi)& 0 & N_2(\xi) \end{array} @f$ **/ for (UInt i = 0; i < spatial_dimension; ++i) for (UInt n = 0; n < size_of_shapes; ++n) N(i, i + spatial_dimension * n) = (*shapes_filt_it)(n); /** * compute stiffness matrix @f$ \mathbf{K} = \delta \mathbf{U}^T * \int_{\Gamma_c} {\mathbf{P}^t \frac{\partial{\mathbf{t}}} *{\partial{\delta}} * \mathbf{P} d\Gamma \Delta \mathbf{U}} @f$ **/ N_A.mul<false, false>(N, A); D_N_A.mul<false, false>(*D_it, N_A); (*At_Nt_D_N_A_it).mul<true, false>(D_N_A, N_A); } delete tangent_stiffness_matrix; delete shapes_filtered; Array<Real> * K_e = new Array<Real>(nb_element, size_at_nt_d_n_a, "K_e"); fem_cohesive.integrate(*at_nt_d_n_a, *K_e, size_at_nt_d_n_a, type, ghost_type, elem_filter); delete at_nt_d_n_a; model->getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _unsymmetric, elem_filter); delete K_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- * * Compute traction from displacements * * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void MaterialCohesive::computeTraction(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Openings", opening); #endif for (auto & type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; UInt nb_quadrature_points = nb_element * fem_cohesive.getNbIntegrationPoints(type, ghost_type); normal.resize(nb_quadrature_points); /// compute normals @f$\mathbf{n}@f$ computeNormal(model->getCurrentPosition(), normal, type, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ computeOpening(model->getDisplacement(), opening(type, ghost_type), type, ghost_type); /// compute traction @f$\mathbf{t}@f$ computeTraction(normal, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeNormal(const Array<Real> & position, Array<Real> & normal, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem_cohesive = this->model->getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine"); #define COMPUTE_NORMAL(type) \ fem_cohesive.getShapeFunctions() \ .computeNormalsOnIntegrationPoints<type, CohesiveReduceFunctionMean>( \ position, normal, ghost_type, element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_NORMAL); #undef COMPUTE_NORMAL AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeOpening(const Array<Real> & displacement, Array<Real> & opening, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem_cohesive = this->model->getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine"); #define COMPUTE_OPENING(type) \ fem_cohesive.getShapeFunctions() \ .interpolateOnIntegrationPoints<type, CohesiveReduceFunctionOpening>( \ displacement, opening, spatial_dimension, ghost_type, \ element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_OPENING); #undef COMPUTE_OPENING AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::updateEnergies(ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (Mesh::getKind(type) != _ek_cohesive) return; Vector<Real> b(spatial_dimension); Vector<Real> h(spatial_dimension); auto erev = reversible_energy(type, ghost_type).begin(); auto etot = total_energy(type, ghost_type).begin(); auto traction_it = tractions(type, ghost_type).begin(spatial_dimension); auto traction_old_it = tractions.previous(type, ghost_type).begin(spatial_dimension); auto opening_it = opening(type, ghost_type).begin(spatial_dimension); auto opening_old_it = opening.previous(type, ghost_type).begin(spatial_dimension); auto traction_end = tractions(type, ghost_type).end(spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++traction_old_it, ++opening_it, ++opening_old_it, ++erev, ++etot) { /// trapezoidal integration b = *opening_it; b -= *opening_old_it; h = *traction_old_it; h += *traction_it; *etot += .5 * b.dot(h); *erev = .5 * traction_it->dot(*opening_it); } /// update old values AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getReversibleEnergy() { AKANTU_DEBUG_IN(); Real erev = 0.; /// integrate reversible energy for each type of elements for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, _ek_cohesive)) { erev += fem_cohesive.integrate(reversible_energy(type, _not_ghost), type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return erev; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getDissipatedEnergy() { AKANTU_DEBUG_IN(); Real edis = 0.; /// integrate dissipated energy for each type of elements for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, _ek_cohesive)) { Array<Real> dissipated_energy(total_energy(type, _not_ghost)); dissipated_energy -= reversible_energy(type, _not_ghost); edis += fem_cohesive.integrate(dissipated_energy, type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return edis; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getContactEnergy() { AKANTU_DEBUG_IN(); Real econ = 0.; /// integrate contact energy for each type of elements for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, _ek_cohesive)) { auto & el_filter = element_filter(type, _not_ghost); UInt nb_quad_per_el = fem_cohesive.getNbIntegrationPoints(type, _not_ghost); UInt nb_quad_points = el_filter.size() * nb_quad_per_el; Array<Real> contact_energy(nb_quad_points); auto contact_traction_it = contact_tractions(type, _not_ghost).begin(spatial_dimension); auto contact_opening_it = contact_opening(type, _not_ghost).begin(spatial_dimension); /// loop on each quadrature point for (UInt q = 0; q < nb_quad_points; ++contact_traction_it, ++contact_opening_it, ++q) { contact_energy(q) = .5 * contact_traction_it->dot(*contact_opening_it); } econ += fem_cohesive.integrate(contact_energy, type, _not_ghost, el_filter); } AKANTU_DEBUG_OUT(); return econ; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getEnergy(const std::string & type) { AKANTU_DEBUG_IN(); if (type == "reversible") return getReversibleEnergy(); else if (type == "dissipated") return getDissipatedEnergy(); else if (type == "cohesive contact") return getContactEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh index 2f854eb40..40ad8a6f3 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh @@ -1,238 +1,237 @@ /** * @file material_cohesive.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jan 12 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Specialization of the material class for cohesive elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material.hh" /* -------------------------------------------------------------------------- */ #include "cohesive_internal_field.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_HH__ #define __AKANTU_MATERIAL_COHESIVE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class SolidMechanicsModelCohesive; } namespace akantu { class MaterialCohesive : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using MyFEEngineCohesiveType = FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>; public: MaterialCohesive(SolidMechanicsModel & model, const ID & id = ""); ~MaterialCohesive() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter void initMaterial() override; /// compute tractions (including normals and openings) void computeTraction(GhostType ghost_type = _not_ghost); /// assemble residual void assembleInternalForces(GhostType ghost_type = _not_ghost) override; /// check stress for cohesive elements' insertion, by default it /// also updates the cohesive elements' data virtual void checkInsertion(bool /*check_only*/ = false) { AKANTU_TO_IMPLEMENT(); } /// interpolate stress on given positions for each element (empty /// implemantation to avoid the generic call to be done on cohesive elements) virtual void interpolateStress(const ElementType /*type*/, Array<Real> & /*result*/) {} /// compute the stresses void computeAllStresses(GhostType /*ghost_type*/ = _not_ghost) override{}; // add the facet to be handled by the material UInt addFacet(const Element & element); protected: virtual void computeTangentTraction(const ElementType & /*el_type*/, Array<Real> & /*tangent_matrix*/, const Array<Real> & /*normal*/, GhostType /*ghost_type*/ = _not_ghost) { AKANTU_TO_IMPLEMENT(); } /// compute the normal void computeNormal(const Array<Real> & position, Array<Real> & normal, ElementType type, GhostType ghost_type); /// compute the opening void computeOpening(const Array<Real> & displacement, Array<Real> & opening, ElementType type, GhostType ghost_type); template <ElementType type> void computeNormal(const Array<Real> & position, Array<Real> & normal, GhostType ghost_type); /// assemble stiffness void assembleStiffnessMatrix(GhostType ghost_type) override; /// constitutive law virtual void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) = 0; /// parallelism functions inline UInt getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const; inline void packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const; inline void unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag); protected: void updateEnergies(ElementType el_type, GhostType ghost_type) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the opening AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Opening, opening, Real); /// get the traction AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Traction, tractions, Real); /// get damage AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real); /// get facet filter AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO(FacetFilter, facet_filter, const ElementTypeMapArray<UInt> &); // AKANTU_GET_MACRO(ElementFilter, element_filter, const // ElementTypeMapArray<UInt> &); /// compute reversible energy Real getReversibleEnergy(); /// compute dissipated energy Real getDissipatedEnergy(); /// compute contact energy Real getContactEnergy(); /// get energy Real getEnergy(const std::string & type) override; /// return the energy (identified by id) for the provided element Real getEnergy(const std::string & energy_id, ElementType type, UInt index) override { return Material::getEnergy(energy_id, type, index); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of facets assigned to this material ElementTypeMapArray<UInt> facet_filter; /// Link to the cohesive fem object in the model FEEngine & fem_cohesive; private: /// reversible energy by quadrature point CohesiveInternalField<Real> reversible_energy; /// total energy by quadrature point CohesiveInternalField<Real> total_energy; protected: /// opening in all elements and quadrature points CohesiveInternalField<Real> opening; /// traction in all elements and quadrature points CohesiveInternalField<Real> tractions; /// traction due to contact CohesiveInternalField<Real> contact_tractions; /// normal openings for contact tractions CohesiveInternalField<Real> contact_opening; /// maximum displacement CohesiveInternalField<Real> delta_max; /// tell if the previous delta_max state is needed (in iterative schemes) bool use_previous_delta_max; /// tell if the previous opening state is needed (in iterative schemes) bool use_previous_opening; /// damage CohesiveInternalField<Real> damage; /// pointer to the solid mechanics model for cohesive elements SolidMechanicsModelCohesive * model; /// critical stress RandomInternalField<Real, FacetInternalField> sigma_c; /// critical displacement Real delta_c; /// array to temporarily store the normals Array<Real> normal; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_inline_impl.cc" } // namespace akantu #include "cohesive_internal_field_tmpl.hh" #endif /* __AKANTU_MATERIAL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_includes.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_includes.hh index 6548a282c..5cd373e11 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_includes.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_includes.hh @@ -1,49 +1,48 @@ /** * @file material_cohesive_includes.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sun Sep 26 2010 - * @date last modification: Tue Jan 12 2016 + * @date last modification: Fri Oct 13 2017 * * @brief List of includes for cohesive elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_CMAKE_LIST_MATERIALS #include "material_cohesive.hh" #include "material_cohesive_bilinear.hh" #include "material_cohesive_exponential.hh" #include "material_cohesive_linear.hh" #include "material_cohesive_linear_fatigue.hh" #include "material_cohesive_linear_friction.hh" #include "material_cohesive_linear_uncoupled.hh" #endif #define AKANTU_COHESIVE_MATERIAL_LIST \ ((2, (cohesive_linear, MaterialCohesiveLinear)))( \ (2, (cohesive_linear_fatigue, MaterialCohesiveLinearFatigue)))( \ (2, (cohesive_linear_friction, MaterialCohesiveLinearFriction)))( \ (2, (cohesive_linear_uncoupled, MaterialCohesiveLinearUncoupled)))( \ (2, (cohesive_bilinear, MaterialCohesiveBilinear)))( \ (2, (cohesive_exponential, MaterialCohesiveExponential))) diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc index 5e6a2cf69..469d804e8 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc @@ -1,102 +1,101 @@ /** * @file material_cohesive_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Aug 04 2010 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Mon Feb 19 2018 * * @brief MaterialCohesive inline implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline UInt MaterialCohesive::addFacet(const Element & element) { Array<UInt> & f_filter = facet_filter(element.type, element.ghost_type); f_filter.push_back(element.element); return f_filter.size() - 1; } /* -------------------------------------------------------------------------- */ template <ElementType type> void MaterialCohesive::computeNormal(const Array<Real> & /*position*/, Array<Real> & /*normal*/, GhostType /*ghost_type*/) {} /* -------------------------------------------------------------------------- */ inline UInt MaterialCohesive::getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const { switch (tag) { case _gst_smm_stress: { return 2 * spatial_dimension * sizeof(Real) * this->getModel().getNbIntegrationPoints(elements, "CohesiveFEEngine"); } case _gst_smmc_damage: { return sizeof(Real) * this->getModel().getNbIntegrationPoints(elements, "CohesiveFEEngine"); } default: {} } return 0; } /* -------------------------------------------------------------------------- */ inline void MaterialCohesive::packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const { switch (tag) { case _gst_smm_stress: { packElementDataHelper(tractions, buffer, elements, "CohesiveFEEngine"); packElementDataHelper(contact_tractions, buffer, elements, "CohesiveFEEngine"); break; } case _gst_smmc_damage: packElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); break; default: {} } } /* -------------------------------------------------------------------------- */ inline void MaterialCohesive::unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) { switch (tag) { case _gst_smm_stress: { unpackElementDataHelper(tractions, buffer, elements, "CohesiveFEEngine"); unpackElementDataHelper(contact_tractions, buffer, elements, "CohesiveFEEngine"); break; } case _gst_smmc_damage: unpackElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); break; default: {} } } diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc index 9e2a9eb12..b6b1bc5cd 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc @@ -1,713 +1,714 @@ /** * @file solid_mechanics_model_cohesive.cc * + * @author Fabian Barras <fabian.barras@epfl.ch> * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 - * @date last modification: Wed Jan 13 2016 + * @date last modification: Wed Feb 21 2018 * * @brief Solid mechanics model for cohesive elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "aka_iterators.hh" #include "cohesive_element_inserter.hh" #include "element_synchronizer.hh" #include "facet_synchronizer.hh" #include "fe_engine_template.hh" #include "integrator_gauss.hh" #include "material_cohesive.hh" #include "parser.hh" #include "shape_cohesive.hh" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::SolidMechanicsModelCohesive( Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, dim, id, memory_id, ModelType::_solid_mechanics_model_cohesive), tangents("tangents", id), facet_stress("facet_stress", id), facet_material("facet_material", id) { AKANTU_DEBUG_IN(); registerFEEngineObject<MyFEEngineCohesiveType>("CohesiveFEEngine", mesh, Model::spatial_dimension); auto && tmp_material_selector = std::make_shared<DefaultMaterialCohesiveSelector>(*this); tmp_material_selector->setFallback(this->material_selector); this->material_selector = tmp_material_selector; #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("cohesive elements", id); this->mesh.addDumpMeshToDumper("cohesive elements", mesh, Model::spatial_dimension, _not_ghost, _ek_cohesive); #endif if (this->mesh.isDistributed()) { /// create the distributed synchronizer for cohesive elements this->cohesive_synchronizer = std::make_unique<ElementSynchronizer>( mesh, "cohesive_distributed_synchronizer"); auto & synchronizer = mesh.getElementSynchronizer(); this->cohesive_synchronizer->split(synchronizer, [](auto && el) { return Mesh::getKind(el.type) == _ek_cohesive; }); this->registerSynchronizer(*cohesive_synchronizer, _gst_material_id); this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_stress); this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_boundary); } this->inserter = std::make_unique<CohesiveElementInserter>( this->mesh, id + ":cohesive_element_inserter"); registerFEEngineObject<MyFEEngineFacetType>( "FacetsFEEngine", mesh.getMeshFacets(), Model::spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::~SolidMechanicsModelCohesive() = default; /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::setTimeStep(Real time_step, const ID & solver_id) { SolidMechanicsModel::setTimeStep(time_step, solver_id); #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper("cohesive elements").setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initFullImpl(const ModelOptions & options) { AKANTU_DEBUG_IN(); const auto & smmc_options = dynamic_cast<const SolidMechanicsModelCohesiveOptions &>(options); this->is_extrinsic = smmc_options.extrinsic; inserter->setIsExtrinsic(is_extrinsic); if (mesh.isDistributed()) { auto & mesh_facets = inserter->getMeshFacets(); auto & synchronizer = dynamic_cast<FacetSynchronizer &>(mesh_facets.getElementSynchronizer()); this->registerSynchronizer(synchronizer, _gst_smmc_facets); this->registerSynchronizer(synchronizer, _gst_smmc_facets_conn); synchronizeGhostFacetsConnectivity(); /// create the facet synchronizer for extrinsic simulations if (is_extrinsic) { facet_stress_synchronizer = std::make_unique<ElementSynchronizer>( synchronizer, id + ":facet_stress_synchronizer"); this->registerSynchronizer(*facet_stress_synchronizer, _gst_smmc_facets_stress); } inserter->initParallel(*cohesive_synchronizer); } ParserSection section; bool is_empty; std::tie(section, is_empty) = this->getParserSection(); if (not is_empty) { auto inserter_section = section.getSubSections(ParserType::_cohesive_inserter); if (inserter_section.begin() != inserter_section.end()) { inserter->parseSection(*inserter_section.begin()); } } SolidMechanicsModel::initFullImpl(options); AKANTU_DEBUG_OUT(); } // namespace akantu /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initMaterials() { AKANTU_DEBUG_IN(); // make sure the material are instantiated if (!are_materials_instantiated) instantiateMaterials(); /// find the first cohesive material UInt cohesive_index = UInt(-1); for (auto && material : enumerate(materials)) { if (dynamic_cast<MaterialCohesive *>(std::get<1>(material).get())) { cohesive_index = std::get<0>(material); break; } } if (cohesive_index == UInt(-1)) AKANTU_EXCEPTION("No cohesive materials in the material input file"); material_selector->setFallback(cohesive_index); // set the facet information in the material in case of dynamic insertion // to know what material to call for stress checks if (is_extrinsic) { this->initExtrinsicMaterials(); } else { this->initIntrinsicMaterials(); } AKANTU_DEBUG_OUT(); } // namespace akantu /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initExtrinsicMaterials() { const Mesh & mesh_facets = inserter->getMeshFacets(); facet_material.initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = material_selector->getFallbackValue()); for_each_element( mesh_facets, [&](auto && element) { auto mat_index = (*material_selector)(element); auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]); facet_material(element) = mat_index; mat.addFacet(element); }, _spatial_dimension = spatial_dimension - 1, _ghost_type = _not_ghost); SolidMechanicsModel::initMaterials(); this->initAutomaticInsertion(); } /* -------------------------------------------------------------------------- */ #if 0 void SolidMechanicsModelCohesive::initIntrinsicCohesiveMaterials( const std::string & cohesive_surfaces) { AKANTU_DEBUG_IN(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) if (facet_synchronizer != nullptr) inserter->initParallel(facet_synchronizer, cohesive_element_synchronizer); // inserter->initParallel(facet_synchronizer, synch_parallel); #endif std::istringstream split(cohesive_surfaces); std::string physname; while (std::getline(split, physname, ',')) { AKANTU_DEBUG_INFO( "Pre-inserting cohesive elements along facets from physical surface: " << physname); insertElementsFromMeshData(physname); } synchronizeInsertionData(); SolidMechanicsModel::initMaterials(); auto && tmp = std::make_shared<MeshDataMaterialCohesiveSelector>(*this); tmp->setFallback(material_selector->getFallbackValue()); tmp->setFallback(material_selector->getFallbackSelector()); material_selector = tmp; // UInt nb_new_elements = inserter->insertElements(); // if (nb_new_elements > 0) { // this->reinitializeSolver(); // } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::synchronizeInsertionData() { if (inserter->getMeshFacets().isDistributed()) { inserter->getMeshFacets().getElementSynchronizer().synchronizeOnce( *inserter, _gst_ce_groups); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initIntrinsicMaterials() { AKANTU_DEBUG_IN(); SolidMechanicsModel::initMaterials(); this->insertIntrinsicElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian */ void SolidMechanicsModelCohesive::initModel() { AKANTU_DEBUG_IN(); SolidMechanicsModel::initModel(); /// add cohesive type connectivity ElementType type = _not_defined; for (auto && type_ghost : ghost_types) { for (const auto & tmp_type : mesh.elementTypes(spatial_dimension, type_ghost)) { const auto & connectivity = mesh.getConnectivity(tmp_type, type_ghost); if (connectivity.size() == 0) continue; type = tmp_type; auto type_facet = Mesh::getFacetType(type); auto type_cohesive = FEEngine::getCohesiveElementType(type_facet); mesh.addConnectivityType(type_cohesive, type_ghost); } } AKANTU_DEBUG_ASSERT(type != _not_defined, "No elements in the mesh"); getFEEngine("CohesiveFEEngine").initShapeFunctions(_not_ghost); getFEEngine("CohesiveFEEngine").initShapeFunctions(_ghost); if (is_extrinsic) { getFEEngine("FacetsFEEngine").initShapeFunctions(_not_ghost); getFEEngine("FacetsFEEngine").initShapeFunctions(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::insertIntrinsicElements() { AKANTU_DEBUG_IN(); inserter->insertIntrinsicElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initAutomaticInsertion() { AKANTU_DEBUG_IN(); this->inserter->limitCheckFacets(); this->updateFacetStressSynchronizer(); this->resizeFacetStress(); /// compute normals on facets this->computeNormals(); this->initStressInterpolation(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateAutomaticInsertion() { AKANTU_DEBUG_IN(); this->inserter->limitCheckFacets(); this->updateFacetStressSynchronizer(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initStressInterpolation() { Mesh & mesh_facets = inserter->getMeshFacets(); /// compute quadrature points coordinates on facets Array<Real> & position = mesh.getNodes(); ElementTypeMapArray<Real> quad_facets("quad_facets", id); quad_facets.initialize(mesh_facets, _nb_component = Model::spatial_dimension, _spatial_dimension = Model::spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(quad_facets, Model::spatial_dimension, // Model::spatial_dimension - 1); getFEEngine("FacetsFEEngine") .interpolateOnIntegrationPoints(position, quad_facets); /// compute elements quadrature point positions and build /// element-facet quadrature points data structure ElementTypeMapArray<Real> elements_quad_facets("elements_quad_facets", id); elements_quad_facets.initialize( mesh, _nb_component = Model::spatial_dimension, _spatial_dimension = Model::spatial_dimension); // mesh.initElementTypeMapArray(elements_quad_facets, // Model::spatial_dimension, // Model::spatial_dimension); for (auto elem_gt : ghost_types) { for (auto & type : mesh.elementTypes(Model::spatial_dimension, elem_gt)) { UInt nb_element = mesh.getNbElement(type, elem_gt); if (nb_element == 0) continue; /// compute elements' quadrature points and list of facet /// quadrature points positions by element const auto & facet_to_element = mesh_facets.getSubelementToElement(type, elem_gt); auto & el_q_facet = elements_quad_facets(type, elem_gt); auto facet_type = Mesh::getFacetType(type); auto nb_quad_per_facet = getFEEngine("FacetsFEEngine").getNbIntegrationPoints(facet_type); auto nb_facet_per_elem = facet_to_element.getNbComponent(); // small hack in the loop to skip boundary elements, they are silently // initialized to NaN to see if this causes problems el_q_facet.resize(nb_element * nb_facet_per_elem * nb_quad_per_facet, std::numeric_limits<Real>::quiet_NaN()); for (auto && data : zip(make_view(facet_to_element), make_view(el_q_facet, spatial_dimension, nb_quad_per_facet))) { const auto & global_facet = std::get<0>(data); auto & el_q = std::get<1>(data); if (global_facet == ElementNull) continue; Matrix<Real> quad_f = make_view(quad_facets(global_facet.type, global_facet.ghost_type), spatial_dimension, nb_quad_per_facet) .begin()[global_facet.element]; el_q = quad_f; // for (UInt q = 0; q < nb_quad_per_facet; ++q) { // for (UInt s = 0; s < Model::spatial_dimension; ++s) { // el_q_facet(el * nb_facet_per_elem * nb_quad_per_facet + // f * nb_quad_per_facet + q, // s) = quad_f(global_facet * nb_quad_per_facet + q, // s); // } // } //} } } } /// loop over non cohesive materials for (auto && material : materials) { if (dynamic_cast<MaterialCohesive *>(material.get())) continue; /// initialize the interpolation function material->initElementalFieldInterpolation(elements_quad_facets); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::assembleInternalForces() { AKANTU_DEBUG_IN(); // f_int += f_int_cohe for (auto & material : this->materials) { try { auto & mat = dynamic_cast<MaterialCohesive &>(*material); mat.computeTraction(_not_ghost); } catch (std::bad_cast & bce) { } } SolidMechanicsModel::assembleInternalForces(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeNormals() { AKANTU_DEBUG_IN(); Mesh & mesh_facets = this->inserter->getMeshFacets(); this->getFEEngine("FacetsFEEngine") .computeNormalsOnIntegrationPoints(_not_ghost); /** * @todo store tangents while computing normals instead of * recomputing them as follows: */ /* ------------------------------------------------------------------------ */ UInt tangent_components = Model::spatial_dimension * (Model::spatial_dimension - 1); tangents.initialize(mesh_facets, _nb_component = tangent_components, _spatial_dimension = Model::spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(tangents, tangent_components, // Model::spatial_dimension - 1); for (auto facet_type : mesh_facets.elementTypes(Model::spatial_dimension - 1)) { const Array<Real> & normals = this->getFEEngine("FacetsFEEngine") .getNormalsOnIntegrationPoints(facet_type); Array<Real> & tangents = this->tangents(facet_type); Math::compute_tangents(normals, tangents); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::interpolateStress() { ElementTypeMapArray<Real> by_elem_result("temporary_stress_by_facets", id); for (auto & material : materials) { auto * mat = dynamic_cast<MaterialCohesive *>(material.get()); if (mat == nullptr) /// interpolate stress on facet quadrature points positions material->interpolateStressOnFacets(facet_stress, by_elem_result); } #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData( debug::_dm_model_cohesive, "Interpolated stresses before", facet_stress); #endif this->synchronize(_gst_smmc_facets_stress); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_model_cohesive, "Interpolated stresses", facet_stress); #endif } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::checkCohesiveStress() { AKANTU_DEBUG_IN(); interpolateStress(); for (auto & mat : materials) { auto * mat_cohesive = dynamic_cast<MaterialCohesive *>(mat.get()); if (mat_cohesive) { /// check which not ghost cohesive elements are to be created mat_cohesive->checkInsertion(); } } /// communicate data among processors this->synchronize(_gst_smmc_facets); /// insert cohesive elements UInt nb_new_elements = inserter->insertElements(); // if (nb_new_elements > 0) { // this->reinitializeSolver(); // } AKANTU_DEBUG_OUT(); return nb_new_elements; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onElementsAdded( const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); updateCohesiveSynchronizers(); SolidMechanicsModel::onElementsAdded(element_list, event); if (cohesive_synchronizer != nullptr) cohesive_synchronizer->computeAllBufferSizes(*this); if (is_extrinsic) resizeFacetStress(); /// if (method != _explicit_lumped_mass) { /// this->initSolver(); /// } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onNodesAdded(const Array<UInt> & new_nodes, const NewNodesEvent & event) { AKANTU_DEBUG_IN(); // Array<UInt> nodes_list(nb_new_nodes); // for (UInt n = 0; n < nb_new_nodes; ++n) // nodes_list(n) = doubled_nodes(n, 1); SolidMechanicsModel::onNodesAdded(new_nodes, event); UInt new_node, old_node; try { const auto & cohesive_event = dynamic_cast<const CohesiveNewNodesEvent &>(event); const auto & old_nodes = cohesive_event.getOldNodesList(); auto copy = [this, &new_node, &old_node](auto & arr) { for (UInt s = 0; s < spatial_dimension; ++s) { arr(new_node, s) = arr(old_node, s); } }; for (auto && pair : zip(new_nodes, old_nodes)) { std::tie(new_node, old_node) = pair; copy(*displacement); copy(*blocked_dofs); if (velocity) copy(*velocity); if (acceleration) copy(*acceleration); if (current_position) copy(*current_position); if (previous_displacement) copy(*previous_displacement); } // if (this->getDOFManager().hasMatrix("M")) { // this->assembleMass(old_nodes); // } // if (this->getDOFManager().hasLumpedMatrix("M")) { // this->assembleMassLumped(old_nodes); // } } catch (std::bad_cast &) { } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onEndSolveStep(const AnalysisMethod &) { AKANTU_DEBUG_IN(); /* * This is required because the Cauchy stress is the stress measure that * is used to check the insertion of cohesive elements */ for (auto & mat : materials) { if (mat->isFiniteDeformation()) mat->computeAllCauchyStresses(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "SolidMechanicsModelCohesive [" << std::endl; SolidMechanicsModel::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::resizeFacetStress() { AKANTU_DEBUG_IN(); this->facet_stress.initialize(getFEEngine("FacetsFEEngine"), _nb_component = 2 * spatial_dimension * spatial_dimension, _spatial_dimension = spatial_dimension - 1); // for (auto && ghost_type : ghost_types) { // for (const auto & type : // mesh_facets.elementTypes(spatial_dimension - 1, ghost_type)) { // UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); // UInt nb_quadrature_points = getFEEngine("FacetsFEEngine") // .getNbIntegrationPoints(type, // ghost_type); // UInt new_size = nb_facet * nb_quadrature_points; // facet_stress(type, ghost_type).resize(new_size); // } // } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::addDumpGroupFieldToDumper( const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { AKANTU_DEBUG_IN(); UInt spatial_dimension = Model::spatial_dimension; ElementKind _element_kind = element_kind; if (dumper_name == "cohesive elements") { _element_kind = _ek_cohesive; } else if (dumper_name == "facets") { spatial_dimension = Model::spatial_dimension - 1; } SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, spatial_dimension, _element_kind, padding_flag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onDump() { this->flattenAllRegisteredInternals(_ek_cohesive); SolidMechanicsModel::onDump(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh index cf149d7b2..49abaabff 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh @@ -1,320 +1,320 @@ /** * @file solid_mechanics_model_cohesive.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Mon Feb 05 2018 * * @brief Solid mechanics model for cohesive elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "material_selector_cohesive.hh" #include "random_internal_field.hh" // included to have the specialization of #include "solid_mechanics_model.hh" #include "solid_mechanics_model_event_handler.hh" // ParameterTyped::operator Real() /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class FacetSynchronizer; class FacetStressSynchronizer; class ElementSynchronizer; } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ struct FacetsCohesiveIntegrationOrderFunctor { template <ElementType type, ElementType cohesive_type = CohesiveFacetProperty<type>::cohesive_type> struct _helper { static constexpr int get() { return ElementClassProperty<cohesive_type>::polynomial_degree; } }; template <ElementType type> struct _helper<type, _not_defined> { static constexpr int get() { return ElementClassProperty<type>::polynomial_degree; } }; template <ElementType type> static inline constexpr int getOrder() { return _helper<type>::get(); } }; /* -------------------------------------------------------------------------- */ /* Solid Mechanics Model for Cohesive elements */ /* -------------------------------------------------------------------------- */ class SolidMechanicsModelCohesive : public SolidMechanicsModel, public SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewCohesiveNodesEvent : public NewNodesEvent { public: AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array<UInt> &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array<UInt> &); protected: Array<UInt> old_nodes; }; using MyFEEngineCohesiveType = FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>; using MyFEEngineFacetType = FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_regular, FacetsCohesiveIntegrationOrderFunctor>; SolidMechanicsModelCohesive(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model_cohesive", const MemoryID & memory_id = 0); ~SolidMechanicsModelCohesive() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize the cohesive model void initFullImpl(const ModelOptions & options) override; public: /// set the value of the time step void setTimeStep(Real time_step, const ID & solver_id = "") override; /// assemble the residual for the explicit scheme void assembleInternalForces() override; /// function to perform a stress check on each facet and insert /// cohesive elements if needed (returns the number of new cohesive /// elements) UInt checkCohesiveStress(); /// interpolate stress on facets void interpolateStress(); /// update automatic insertion after a change in the element inserter void updateAutomaticInsertion(); /// insert intrinsic cohesive elements void insertIntrinsicElements(); // template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria // criteria> bool solveStepCohesive(Real tolerance, Real & error, UInt // max_iteration = 100, // bool load_reduction = false, // Real tol_increase_factor = 1.0, // bool do_not_factorize = false); protected: /// initialize stress interpolation void initStressInterpolation(); /// initialize the model void initModel() override; /// initialize cohesive material void initMaterials() override; /// init facet filters for cohesive materials void initFacetFilter(); // synchronize facets physical data before insertion along physical surfaces void synchronizeInsertionData(); /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override; private: /// initialize cohesive material with extrinsic insertion void initExtrinsicMaterials(); /// initialize cohesive material with intrinsic insertion void initIntrinsicMaterials(); /// insert cohesive elements along a given physical surface of the mesh void insertElementsFromMeshData(const std::string & physical_name); /// initialize completely the model for extrinsic elements void initAutomaticInsertion(); /// compute facets' normals void computeNormals(); /// resize facet stress void resizeFacetStress(); /// init facets_check array void initFacetsCheck(); /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: void onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) override; void onElementsAdded(const Array<Element> & nodes_list, const NewElementsEvent & event) override; /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: void onEndSolveStep(const AnalysisMethod & method) override; /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: void onDump() override; void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) override; public: /// register the tags associated with the parallel synchronizer for /// cohesive elements // void initParallel(MeshPartition * partition, // DataAccessor * data_accessor = NULL, // bool extrinsic = false); protected: void synchronizeGhostFacetsConnectivity(); void updateCohesiveSynchronizers(); void updateFacetStressSynchronizer(); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; protected: UInt getNbQuadsForFacetCheck(const Array<Element> & elements) const; template <typename T> void packFacetStressDataHelper(const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const; template <typename T> void unpackFacetStressDataHelper(ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements) const; template <typename T, bool pack_helper> void packUnpackFacetStressDataHelper(ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & element) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get facet mesh AKANTU_GET_MACRO(MeshFacets, mesh.getMeshFacets(), const Mesh &); /// get stress on facets vector AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(StressOnFacets, facet_stress, Real); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO(FacetMaterial, facet_material, const ElementTypeMapArray<UInt> &); /// @todo THIS HAS TO BE CHANGED AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Tangents, tangents, Real); /// get element inserter AKANTU_GET_MACRO_NOT_CONST(ElementInserter, *inserter, CohesiveElementInserter &); /// get is_extrinsic boolean AKANTU_GET_MACRO(IsExtrinsic, is_extrinsic, bool); /// get cohesive elements synchronizer AKANTU_GET_MACRO(CohesiveSynchronizer, *cohesive_synchronizer, const ElementSynchronizer &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// @todo store tangents when normals are computed: ElementTypeMapArray<Real> tangents; /// stress on facets on the two sides by quadrature point ElementTypeMapArray<Real> facet_stress; /// material to use if a cohesive element is created on a facet ElementTypeMapArray<UInt> facet_material; bool is_extrinsic; /// cohesive element inserter std::unique_ptr<CohesiveElementInserter> inserter; /// facet stress synchronizer std::unique_ptr<ElementSynchronizer> facet_stress_synchronizer; /// cohesive elements synchronizer std::unique_ptr<ElementSynchronizer> cohesive_synchronizer; /// global connectivity ElementTypeMapArray<UInt> * global_connectivity; }; } // namespace akantu #include "solid_mechanics_model_cohesive_inline_impl.cc" #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_inline_impl.cc index bf3a809e3..43403bf43 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_inline_impl.cc @@ -1,305 +1,306 @@ /** * @file solid_mechanics_model_cohesive_inline_impl.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jan 18 2013 - * @date last modification: Thu Jan 14 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of inline functions for the Cohesive element model * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ // template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> // bool SolidMechanicsModelCohesive::solveStepCohesive( // Real tolerance, Real & error, UInt max_iteration, bool load_reduction, // Real tol_increase_factor, bool do_not_factorize) { // // EventManager::sendEvent( // // SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); // // this->implicitPred(); // // bool insertion_new_element = true; // // bool converged = false; // // Array<Real> * displacement_tmp = NULL; // // Array<Real> * velocity_tmp = NULL; // // Array<Real> * acceleration_tmp = NULL; // // StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); // // Int prank = comm.whoAmI(); // // /// Loop for the insertion of new cohesive elements // // while (insertion_new_element) { // // if (is_extrinsic) { // // /** // // * If in extrinsic the solution of the previous incremental step // // * is saved in temporary arrays created for displacements, // // * velocities and accelerations. Such arrays are used to find // // * the solution with the Newton-Raphson scheme (this is done by // // * pointing the pointer "displacement" to displacement_tmp). In // // * this way, inside the array "displacement" is kept the // // * solution of the previous incremental step, and in // // * "displacement_tmp" is saved the current solution. // // */ // // if (!displacement_tmp) // // displacement_tmp = new Array<Real>(0, spatial_dimension); // // displacement_tmp->copy(*(this->displacement)); // // if (!velocity_tmp) // // velocity_tmp = new Array<Real>(0, spatial_dimension); // // velocity_tmp->copy(*(this->velocity)); // // if (!acceleration_tmp) { // // acceleration_tmp = new Array<Real>(0, spatial_dimension); // // } // // acceleration_tmp->copy(*(this->acceleration)); // // std::swap(displacement, displacement_tmp); // // std::swap(velocity, velocity_tmp); // // std::swap(acceleration, acceleration_tmp); // // } // // this->updateResidual(); // // AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL, // // "You should first initialize the implicit solver and // " // // "assemble the stiffness matrix"); // // bool need_factorize = !do_not_factorize; // // if (method == _implicit_dynamic) { // // AKANTU_DEBUG_ASSERT(mass_matrix != NULL, "You should first initialize // " // // "the implicit solver and " // // "assemble the mass matrix"); // // } // // switch (cmethod) { // // case _scm_newton_raphson_tangent: // // case _scm_newton_raphson_tangent_not_computed: // // break; // // case _scm_newton_raphson_tangent_modified: // // this->assembleStiffnessMatrix(); // // break; // // default: // // AKANTU_ERROR("The resolution method " // // << cmethod << " has not been implemented!"); // // } // // UInt iter = 0; // // converged = false; // // error = 0.; // // if (criteria == _scc_residual) { // // converged = this->testConvergence<criteria>(tolerance, error); // // if (converged) // // return converged; // // } // // /// Loop to solve the nonlinear system // // do { // // if (cmethod == _scm_newton_raphson_tangent) // // this->assembleStiffnessMatrix(); // // solve<NewmarkBeta::_displacement_corrector>(*increment, 1., // // need_factorize); // // this->implicitCorr(); // // this->updateResidual(); // // converged = this->testConvergence<criteria>(tolerance, error); // // iter++; // // AKANTU_DEBUG_INFO("[" << criteria << "] Convergence iteration " // // << std::setw(std::log10(max_iteration)) << iter // // << ": error " << error // // << (converged ? " < " : " > ") << tolerance); // // switch (cmethod) { // // case _scm_newton_raphson_tangent: // // need_factorize = true; // // break; // // case _scm_newton_raphson_tangent_not_computed: // // case _scm_newton_raphson_tangent_modified: // // need_factorize = false; // // break; // // default: // // AKANTU_ERROR("The resolution method " // // << cmethod << " has not been implemented!"); // // } // // } while (!converged && iter < max_iteration); // // /** // // * This is to save the obtained result and proceed with the // // * simulation even if the error is higher than the pre-fixed // // * tolerance. This is done only after loading reduction // // * (load_reduction = true). // // */ // // // if (load_reduction && (error < tolerance * tol_increase_factor)) // // // converged = true; // // if ((error < tolerance * tol_increase_factor)) // // converged = true; // // if (converged) { // // } else if (iter == max_iteration) { // // if (prank == 0) { // // AKANTU_DEBUG_WARNING( // // "[" << criteria << "] Convergence not reached after " // // << std::setw(std::log10(max_iteration)) << iter << " // iteration" // // << (iter == 1 ? "" : "s") << "!" << std::endl); // // } // // } // // if (is_extrinsic) { // // /** // // * If is extrinsic the pointer "displacement" is moved back to // // * the array displacement. In this way, the array displacement is // // * correctly resized during the checkCohesiveStress function (in // // * case new cohesive elements are added). This is possible // // * because the procedure called by checkCohesiveStress does not // // * use the displacement field (the correct one is now stored in // // * displacement_tmp), but directly the stress field that is // // * already computed. // // */ // // Array<Real> * tmp_swap; // // tmp_swap = displacement_tmp; // // displacement_tmp = this->displacement; // // this->displacement = tmp_swap; // // tmp_swap = velocity_tmp; // // velocity_tmp = this->velocity; // // this->velocity = tmp_swap; // // tmp_swap = acceleration_tmp; // // acceleration_tmp = this->acceleration; // // this->acceleration = tmp_swap; // // /// If convergence is reached, call checkCohesiveStress in order // // /// to check if cohesive elements have to be introduced // // if (converged) { // // UInt new_cohesive_elements = checkCohesiveStress(); // // if (new_cohesive_elements == 0) { // // insertion_new_element = false; // // } else { // // insertion_new_element = true; // // } // // } // // } // // if (!converged && load_reduction) // // insertion_new_element = false; // // /** // // * If convergence is not reached, there is the possibility to // // * return back to the main file and reduce the load. Before doing // // * this, a pre-fixed value as to be defined for the parameter // // * delta_max of the cohesive elements introduced in the current // // * incremental step. This is done by calling the function // // * checkDeltaMax. // // */ // // if (!converged) { // // insertion_new_element = false; // // for (UInt m = 0; m < materials.size(); ++m) { // // try { // // MaterialCohesive & mat = // // dynamic_cast<MaterialCohesive &>(*materials[m]); // // mat.checkDeltaMax(_not_ghost); // // } catch (std::bad_cast &) { // // } // // } // // } // // } // end loop for the insertion of new cohesive elements // // /** // // * When the solution to the current incremental step is computed (no // // * more cohesive elements have to be introduced), call the function // // * to compute the energies. // // */ // // if ((is_extrinsic && converged)) { // // for (UInt m = 0; m < materials.size(); ++m) { // // try { // // MaterialCohesive & mat = // // dynamic_cast<MaterialCohesive &>(*materials[m]); // // mat.computeEnergies(); // // } catch (std::bad_cast & bce) { // // } // // } // // EventManager::sendEvent( // // SolidMechanicsModelEvent::AfterSolveStepEvent(method)); // // /** // // * The function resetVariables is necessary to correctly set a // // * variable that permit to decrease locally the penalty parameter // // * for compression. // // */ // // for (UInt m = 0; m < materials.size(); ++m) { // // try { // // MaterialCohesive & mat = // // dynamic_cast<MaterialCohesive &>(*materials[m]); // // mat.resetVariables(_not_ghost); // // } catch (std::bad_cast &) { // // } // // } // // /// The correct solution is saved // // this->displacement->copy(*displacement_tmp); // // this->velocity->copy(*velocity_tmp); // // this->acceleration->copy(*acceleration_tmp); // // } // // delete displacement_tmp; // // delete velocity_tmp; // // delete acceleration_tmp; // // return insertion_new_element; //} } // akantu #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc index da79875ba..7735e5e55 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc @@ -1,488 +1,505 @@ /** * @file solid_mechanics_model_cohesive_parallel.cc * + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * + * @date creation: Wed Nov 05 2014 + * @date last modification: Tue Feb 20 2018 * * @brief Functions for parallel cohesive elements * * @section LICENSE * - * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 <http://www.gnu.org/licenses/>. + * */ + /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "element_synchronizer.hh" #include "material_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "solid_mechanics_model_tmpl.hh" /* -------------------------------------------------------------------------- */ #include <type_traits> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::synchronizeGhostFacetsConnectivity() { AKANTU_DEBUG_IN(); const Communicator & comm = mesh.getCommunicator(); Int psize = comm.getNbProc(); if (psize > 1) { /// get global connectivity for not ghost facets global_connectivity = new ElementTypeMapArray<UInt>("global_connectivity", id); auto & mesh_facets = inserter->getMeshFacets(); global_connectivity->initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _with_nb_nodes_per_element = true, _element_kind = _ek_regular); mesh_facets.getGlobalConnectivity(*global_connectivity); /// communicate synchronize(_gst_smmc_facets_conn); /// flip facets MeshUtils::flipFacets(mesh_facets, *global_connectivity, _ghost); delete global_connectivity; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateCohesiveSynchronizers() { /// update synchronizers if needed if (not mesh.isDistributed()) return; auto & mesh_facets = inserter->getMeshFacets(); auto & facet_synchronizer = mesh_facets.getElementSynchronizer(); const auto & cfacet_synchronizer = facet_synchronizer; // update the cohesive element synchronizer cohesive_synchronizer->updateSchemes([&](auto && scheme, auto && proc, auto && direction) { auto & facet_scheme = cfacet_synchronizer.getCommunications().getScheme(proc, direction); for (auto && facet : facet_scheme) { const auto & connected_elements = mesh_facets.getElementToSubelement( facet.type, facet.ghost_type)(facet.element); // slow access here const auto & cohesive_element = connected_elements[1]; if (cohesive_element == ElementNull or cohesive_element.kind() == _ek_cohesive) continue; auto && cohesive_type = FEEngine::getCohesiveElementType(facet.type); auto old_nb_cohesive_elements = mesh.getNbElement(cohesive_type, facet.ghost_type); old_nb_cohesive_elements -= mesh_facets .getData<UInt>("facet_to_double", facet.type, facet.ghost_type) .size(); if (cohesive_element.element >= old_nb_cohesive_elements) { scheme.push_back(cohesive_element); } } }); const auto & comm = mesh.getCommunicator(); auto && my_rank = comm.whoAmI(); // update the facet stress synchronizer if (facet_stress_synchronizer) facet_stress_synchronizer->updateSchemes([&](auto && scheme, auto && proc, auto && /*direction*/) { auto it_element = scheme.begin(); for (auto && element : scheme) { auto && facet_check = inserter->getCheckFacets( element.type, element.ghost_type)(element.element); // slow access // here if (facet_check) { auto && connected_elements = mesh_facets.getElementToSubelement( element.type, element.ghost_type)(element.element); // slow access // here auto && rank_left = facet_synchronizer.getRank(connected_elements[0]); auto && rank_right = facet_synchronizer.getRank(connected_elements[1]); // keep element if the element is still a boundary element between two // processors if ((rank_left == Int(proc) and rank_right == my_rank) or (rank_left == my_rank and rank_right == Int(proc))) { *it_element = element; ++it_element; } } } scheme.resize(it_element - scheme.begin()); }); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateFacetStressSynchronizer() { if (facet_stress_synchronizer != nullptr) { const auto & rank_to_element = mesh.getElementSynchronizer().getElementToRank(); const auto & facet_checks = inserter->getCheckFacets(); const auto & mesh_facets = inserter->getMeshFacets(); const auto & element_to_facet = mesh_facets.getElementToSubelement(); UInt rank = mesh.getCommunicator().whoAmI(); facet_stress_synchronizer->updateSchemes( [&](auto & scheme, auto & proc, auto & /*direction*/) { UInt el = 0; for (auto && element : scheme) { if (not facet_checks(element)) continue; const auto & next_el = element_to_facet(element); UInt rank_left = rank_to_element(next_el[0]); UInt rank_right = rank_to_element(next_el[1]); if ((rank_left == rank and rank_right == proc) or (rank_left == proc and rank_right == rank)) { scheme[el] = element; ++el; } } scheme.resize(el); }); } } /* -------------------------------------------------------------------------- */ template <typename T> void SolidMechanicsModelCohesive::packFacetStressDataHelper( const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const { packUnpackFacetStressDataHelper<T, true>( const_cast<ElementTypeMapArray<T> &>(data_to_pack), buffer, elements); } /* -------------------------------------------------------------------------- */ template <typename T> void SolidMechanicsModelCohesive::unpackFacetStressDataHelper( ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements) const { packUnpackFacetStressDataHelper<T, false>(data_to_unpack, buffer, elements); } /* -------------------------------------------------------------------------- */ template <typename T, bool pack_helper> void SolidMechanicsModelCohesive::packUnpackFacetStressDataHelper( ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt nb_quad_per_elem = 0; UInt sp2 = spatial_dimension * spatial_dimension; UInt nb_component = sp2 * 2; bool element_rank = false; Mesh & mesh_facets = inserter->getMeshFacets(); Array<T> * vect = nullptr; Array<std::vector<Element>> * element_to_facet = nullptr; auto & fe_engine = this->getFEEngine("FacetsFEEngine"); for (auto && el : elements) { if (el.type == _not_defined) AKANTU_EXCEPTION( "packUnpackFacetStressDataHelper called with wrong inputs"); if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; vect = &data_to_pack(el.type, el.ghost_type); element_to_facet = &(mesh_facets.getElementToSubelement(el.type, el.ghost_type)); nb_quad_per_elem = fe_engine.getNbIntegrationPoints(el.type, el.ghost_type); } if (pack_helper) element_rank = (*element_to_facet)(el.element)[0].ghost_type != _not_ghost; else element_rank = (*element_to_facet)(el.element)[0].ghost_type == _not_ghost; for (UInt q = 0; q < nb_quad_per_elem; ++q) { Vector<T> data(vect->storage() + (el.element * nb_quad_per_elem + q) * nb_component + element_rank * sp2, sp2); if (pack_helper) buffer << data; else buffer >> data; } } } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::getNbQuadsForFacetCheck( const Array<Element> & elements) const { UInt nb_quads = 0; UInt nb_quad_per_facet = 0; ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; auto & fe_engine = this->getFEEngine("FacetsFEEngine"); for (auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; nb_quad_per_facet = fe_engine.getNbIntegrationPoints(el.type, el.ghost_type); } nb_quads += nb_quad_per_facet; } return nb_quads; } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::getNbData( const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if (elements.size() == 0) return 0; /// regular element case if (elements(0).kind() == _ek_regular) { switch (tag) { case _gst_smmc_facets: { size += elements.size() * sizeof(bool); break; } case _gst_smmc_facets_conn: { UInt nb_nodes = Mesh::getNbNodesPerElementList(elements); size += nb_nodes * sizeof(UInt); break; } case _gst_smmc_facets_stress: { UInt nb_quads = getNbQuadsForFacetCheck(elements); size += nb_quads * spatial_dimension * spatial_dimension * sizeof(Real); break; } case _gst_material_id: { for (auto && element : elements) { if (Mesh::getSpatialDimension(element.type) == (spatial_dimension - 1)) size += sizeof(UInt); } size += SolidMechanicsModel::getNbData(elements, tag); break; } default: { size += SolidMechanicsModel::getNbData(elements, tag); } } } /// cohesive element case else if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { size += elements.size() * sizeof(UInt); break; } case _gst_smm_boundary: { UInt nb_nodes_per_element = 0; for (auto && el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } default: break; } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { size += mat.getNbData(elements, tag); }); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::packData( CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); if (elements.size() == 0) return; if (elements(0).kind() == _ek_regular) { switch (tag) { case _gst_smmc_facets: { packElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_conn: { packElementalDataHelper(*global_connectivity, buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_stress: { packFacetStressDataHelper(facet_stress, buffer, elements); break; } case _gst_material_id: { for (auto && element : elements) { if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1)) continue; buffer << material_index(element); } SolidMechanicsModel::packData(buffer, elements, tag); break; } default: { SolidMechanicsModel::packData(buffer, elements, tag); } } AKANTU_DEBUG_OUT(); return; } if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { packElementalDataHelper(material_index, buffer, elements, false, getFEEngine("CohesiveFEEngine")); break; } case _gst_smm_boundary: { packNodalDataHelper(*internal_force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.packData(buffer, elements, tag); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (elements.size() == 0) return; if (elements(0).kind() == _ek_regular) { switch (tag) { case _gst_smmc_facets: { unpackElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_conn: { unpackElementalDataHelper(*global_connectivity, buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_stress: { unpackFacetStressDataHelper(facet_stress, buffer, elements); break; } case _gst_material_id: { for (auto && element : elements) { if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1)) continue; UInt recv_mat_index; buffer >> recv_mat_index; UInt & mat_index = material_index(element); if (mat_index != UInt(-1)) continue; // add ghosts element to the correct material mat_index = recv_mat_index; auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]); mat.addFacet(element); facet_material(element) = recv_mat_index; } SolidMechanicsModel::unpackData(buffer, elements, tag); break; } default: { SolidMechanicsModel::unpackData(buffer, elements, tag); } } AKANTU_DEBUG_OUT(); return; } if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { unpackElementalDataHelper(material_index, buffer, elements, false, getFEEngine("CohesiveFEEngine")); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*internal_force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.unpackData(buffer, elements, tag); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.cc b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.cc index f961c7a7c..a422e9b0d 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.cc @@ -1,179 +1,179 @@ /** * @file embedded_interface_intersector.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri May 01 2015 - * @date last modification: Mon Jan 04 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Class that loads the interface from mesh and computes intersections * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "embedded_interface_intersector.hh" #include "mesh_segment_intersector.hh" /// Helper macro for types in the mesh. Creates an intersector and computes /// intersection queries #define INTERFACE_INTERSECTOR_CASE(dim, type) \ do { \ MeshSegmentIntersector<dim, type> intersector(this->mesh, interface_mesh); \ name_to_primitives_it = name_to_primitives_map.begin(); \ for (; name_to_primitives_it != name_to_primitives_end; \ ++name_to_primitives_it) { \ intersector.setPhysicalName(name_to_primitives_it->first); \ intersector.buildResultFromQueryList(name_to_primitives_it->second); \ } \ } while (0) #define INTERFACE_INTERSECTOR_CASE_2D(type) INTERFACE_INTERSECTOR_CASE(2, type) #define INTERFACE_INTERSECTOR_CASE_3D(type) INTERFACE_INTERSECTOR_CASE(3, type) namespace akantu { EmbeddedInterfaceIntersector::EmbeddedInterfaceIntersector( Mesh & mesh, const Mesh & primitive_mesh) : MeshGeomAbstract(mesh), interface_mesh(mesh.getSpatialDimension(), "interface_mesh"), primitive_mesh(primitive_mesh) { // Initiating mesh connectivity and data interface_mesh.addConnectivityType(_segment_2, _not_ghost); interface_mesh.addConnectivityType(_segment_2, _ghost); interface_mesh.registerData<Element>("associated_element") .alloc(0, 1, _segment_2); interface_mesh.registerData<std::string>("physical_names") .alloc(0, 1, _segment_2); } EmbeddedInterfaceIntersector::~EmbeddedInterfaceIntersector() {} void EmbeddedInterfaceIntersector::constructData(GhostType /*ghost_type*/) { AKANTU_DEBUG_IN(); const UInt dim = this->mesh.getSpatialDimension(); if (dim == 1) AKANTU_ERROR( "No embedded model in 1D. Deactivate intersection initialization"); Array<std::string> * physical_names = NULL; try { physical_names = &const_cast<Array<std::string> &>( this->primitive_mesh.getData<std::string>("physical_names", _segment_2)); } catch (debug::Exception & e) { AKANTU_ERROR("You must define physical names to reinforcements in " "order to use the embedded model"); throw e; } const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_segment_2); Array<UInt>::const_vector_iterator connectivity = primitive_mesh.getConnectivity(_segment_2).begin(nb_nodes_per_element); Array<std::string>::scalar_iterator names_it = physical_names->begin(), names_end = physical_names->end(); std::map<std::string, std::list<K::Segment_3>> name_to_primitives_map; // Loop over the physical names and register segment lists in // name_to_primitives_map for (; names_it != names_end; ++names_it) { UInt element_id = names_it - physical_names->begin(); const Vector<UInt> el_connectivity = connectivity[element_id]; K::Segment_3 segment = this->createSegment(el_connectivity); name_to_primitives_map[*names_it].push_back(segment); } // Loop over the background types of the mesh Mesh::type_iterator type_it = this->mesh.firstType(dim, _not_ghost), type_end = this->mesh.lastType(dim, _not_ghost); std::map<std::string, std::list<K::Segment_3>>::iterator name_to_primitives_it, name_to_primitives_end = name_to_primitives_map.end(); for (; type_it != type_end; ++type_it) { // Used in AKANTU_BOOST_ELEMENT_SWITCH ElementType type = *type_it; AKANTU_DEBUG_INFO("Computing intersections with background element type " << type); switch (dim) { case 1: break; case 2: // Compute intersections for supported 2D elements AKANTU_BOOST_ELEMENT_SWITCH(INTERFACE_INTERSECTOR_CASE_2D, (_triangle_3)(_triangle_6)); break; case 3: // Compute intersections for supported 3D elements AKANTU_BOOST_ELEMENT_SWITCH(INTERFACE_INTERSECTOR_CASE_3D, (_tetrahedron_4)); break; } } AKANTU_DEBUG_OUT(); } K::Segment_3 EmbeddedInterfaceIntersector::createSegment(const Vector<UInt> & connectivity) { AKANTU_DEBUG_IN(); K::Point_3 *source = NULL, *target = NULL; const Array<Real> & nodes = this->primitive_mesh.getNodes(); if (this->mesh.getSpatialDimension() == 2) { source = new K::Point_3(nodes(connectivity(0), 0), nodes(connectivity(0), 1), 0.); target = new K::Point_3(nodes(connectivity(1), 0), nodes(connectivity(1), 1), 0.); } else if (this->mesh.getSpatialDimension() == 3) { source = new K::Point_3(nodes(connectivity(0), 0), nodes(connectivity(0), 1), nodes(connectivity(0), 2)); target = new K::Point_3(nodes(connectivity(1), 0), nodes(connectivity(1), 1), nodes(connectivity(1), 2)); } K::Segment_3 segment(*source, *target); delete source; delete target; AKANTU_DEBUG_OUT(); return segment; } } // namespace akantu #undef INTERFACE_INTERSECTOR_CASE #undef INTERFACE_INTERSECTOR_CASE_2D #undef INTERFACE_INTERSECTOR_CASE_3D diff --git a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.hh b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.hh index 03bf41fb0..9552e178b 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.hh @@ -1,98 +1,98 @@ /** * @file embedded_interface_intersector.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri May 01 2015 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Class that loads the interface from mesh and computes intersections * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_EMBEDDED_INTERFACE_INTERSECTOR_HH__ #define __AKANTU_EMBEDDED_INTERFACE_INTERSECTOR_HH__ #include "aka_common.hh" #include "mesh_geom_abstract.hh" #include "mesh_geom_common.hh" #include "mesh_segment_intersector.hh" /* -------------------------------------------------------------------------- */ namespace akantu { namespace { using K = cgal::Cartesian; } /** * @brief Computes the intersections of the reinforcements defined in the * primitive mesh * * The purpose of this class is to look for reinforcements in the primitive * mesh, which * should be defined by physical groups with the same names as the reinforcement * materials * in the model. * * It then constructs the CGAL primitives from the elements of those * reinforcements * and computes the intersections with the background mesh, to create an * `interface_mesh`, * which is in turn used by the EmbeddedInterfaceModel. * * @see MeshSegmentIntersector, MeshGeomAbstract * @see EmbeddedInterfaceModel */ class EmbeddedInterfaceIntersector : public MeshGeomAbstract { public: /// Construct from mesh and a reinforcement mesh explicit EmbeddedInterfaceIntersector(Mesh & mesh, const Mesh & primitive_mesh); /// Destructor virtual ~EmbeddedInterfaceIntersector(); public: /// Generate the interface mesh virtual void constructData(GhostType ghost_type = _not_ghost); /// Create a segment with an element connectivity K::Segment_3 createSegment(const Vector<UInt> & connectivity); /// Getter for interface mesh AKANTU_GET_MACRO_NOT_CONST(InterfaceMesh, interface_mesh, Mesh &); protected: /// Resulting mesh of intersection Mesh interface_mesh; /// Mesh used for primitive construction const Mesh & primitive_mesh; }; } // akantu #endif // __AKANTU_EMBEDDED_INTERFACE_INTERSECTOR_HH__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc index c951110c8..4c260b2df 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc @@ -1,173 +1,173 @@ /** * @file embedded_interface_model.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Mar 13 2015 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Wed Feb 14 2018 * * @brief Model of Solid Mechanics with embedded interfaces * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "embedded_interface_model.hh" #include "integrator_gauss.hh" #include "material_elastic.hh" #include "material_reinforcement.hh" #include "mesh_iterators.hh" #include "shape_lagrange.hh" #ifdef AKANTU_USE_IOHELPER #include "dumpable_inline_impl.hh" #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ EmbeddedInterfaceModel::EmbeddedInterfaceModel(Mesh & mesh, Mesh & primitive_mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, spatial_dimension, id, memory_id), intersector(mesh, primitive_mesh), interface_mesh(nullptr), primitive_mesh(primitive_mesh), interface_material_selector(nullptr) { this->model_type = ModelType::_embedded_model; // This pointer should be deleted by ~SolidMechanicsModel() auto mat_sel_pointer = std::make_shared<MeshDataMaterialSelector<std::string>>("physical_names", *this); this->setMaterialSelector(mat_sel_pointer); interface_mesh = &(intersector.getInterfaceMesh()); // Create 1D FEEngine on the interface mesh registerFEEngineObject<MyFEEngineType>("EmbeddedInterfaceFEEngine", *interface_mesh, 1); // Registering allocator for material reinforcement MaterialFactory::getInstance().registerAllocator( "reinforcement", [&](UInt dim, const ID & constitutive, SolidMechanicsModel &, const ID & id) -> std::unique_ptr<Material> { if (constitutive == "elastic") { using mat = MaterialElastic<1>; switch (dim) { case 2: return std::make_unique<MaterialReinforcement<mat, 2>>(*this, id); case 3: return std::make_unique<MaterialReinforcement<mat, 3>>(*this, id); default: AKANTU_EXCEPTION("Dimension 1 is invalid for reinforcements"); } } else { AKANTU_EXCEPTION("Reinforcement type" << constitutive << " is not recognized"); } }); } /* -------------------------------------------------------------------------- */ EmbeddedInterfaceModel::~EmbeddedInterfaceModel() { delete interface_material_selector; } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::initFullImpl(const ModelOptions & options) { const auto & eim_options = dynamic_cast<const EmbeddedInterfaceModelOptions &>(options); // Do no initialize interface_mesh if told so if (eim_options.has_intersections) intersector.constructData(); SolidMechanicsModel::initFullImpl(options); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("reinforcement", id); this->mesh.addDumpMeshToDumper("reinforcement", *interface_mesh, 1, _not_ghost, _ek_regular); #endif } void EmbeddedInterfaceModel::initModel() { // Initialize interface FEEngine SolidMechanicsModel::initModel(); FEEngine & engine = getFEEngine("EmbeddedInterfaceFEEngine"); engine.initShapeFunctions(_not_ghost); engine.initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::assignMaterialToElements( const ElementTypeMapArray<UInt> * filter) { delete interface_material_selector; interface_material_selector = new InterfaceMeshDataMaterialSelector<std::string>("physical_names", *this); for_each_element(getInterfaceMesh(), [&](auto && element) { auto mat_index = (*interface_material_selector)(element); // material_index(element) = mat_index; materials[mat_index]->addElement(element); // this->material_local_numbering(element) = index; }, _element_filter = filter, _spatial_dimension = 1); SolidMechanicsModel::assignMaterialToElements(filter); } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::addDumpGroupFieldToDumper( const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { #ifdef AKANTU_USE_IOHELPER dumper::Field * field = NULL; // If dumper is reinforcement, create a 1D elemental field if (dumper_name == "reinforcement") field = this->createElementalField(field_id, group_name, padding_flag, 1, element_kind); else { try { SolidMechanicsModel::addDumpGroupFieldToDumper( dumper_name, field_id, group_name, element_kind, padding_flag); } catch (...) { } } if (field) { DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name, group_name); Model::addDumpGroupFieldToDumper(field_id, field, dumper); } #endif } } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.hh b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.hh index 836661b31..42db35d34 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.hh @@ -1,154 +1,153 @@ /** * @file embedded_interface_model.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Mon Dec 14 2015 + * @date last modification: Wed Jan 31 2018 * * @brief Model of Solid Mechanics with embedded interfaces * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ #define __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ #include "aka_common.hh" #include "mesh.hh" #include "solid_mechanics_model.hh" #include "embedded_interface_intersector.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /** * @brief Solid mechanics model using the embedded model. * * This SolidMechanicsModel subclass implements the embedded model, * a method used to represent 1D elements in a finite elements model * (eg. reinforcements in concrete). * * In addition to the SolidMechanicsModel properties, this model has * a mesh of the 1D elements embedded in the model, and an instance of the * EmbeddedInterfaceIntersector class for the computation of the intersections * of the * 1D elements with the background (bulk) mesh. * * @see MaterialReinforcement */ class EmbeddedInterfaceModel : public SolidMechanicsModel { using MyFEEngineType = SolidMechanicsModel::MyFEEngineType; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /** * @brief Constructor * * @param mesh main mesh (concrete) * @param primitive_mesh mesh of the embedded reinforcement */ EmbeddedInterfaceModel(Mesh & mesh, Mesh & primitive_mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "embedded_interface_model", const MemoryID & memory_id = 0); /// Destructor ~EmbeddedInterfaceModel() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Initialise the model void initFullImpl( const ModelOptions & options = EmbeddedInterfaceModelOptions()) override; /// Initialise the materials void assignMaterialToElements(const ElementTypeMapArray<UInt> * filter) override; /// Initialize the embedded shape functions void initModel() override; /// Allows filtering of dump fields which need to be dumpes on interface mesh void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) override; // virtual ElementTypeMap<UInt> getInternalDataPerElem(const std::string & // field_name, // const ElementKind & // kind); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get interface mesh AKANTU_GET_MACRO(InterfaceMesh, *interface_mesh, Mesh &); /// Get associated elements AKANTU_GET_MACRO_BY_ELEMENT_TYPE( InterfaceAssociatedElements, interface_mesh->getData<Element>("associated_element"), Element); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Intersector object to build the interface mesh EmbeddedInterfaceIntersector intersector; /// Interface mesh (weak reference) Mesh * interface_mesh; /// Mesh used to create the CGAL primitives for intersections Mesh & primitive_mesh; /// Material selector for interface MaterialSelector * interface_material_selector; }; /// Material selector based on mesh data for interface elements template <typename T> class InterfaceMeshDataMaterialSelector : public ElementDataMaterialSelector<T> { public: InterfaceMeshDataMaterialSelector(const std::string & name, const EmbeddedInterfaceModel & model, UInt first_index = 1) : ElementDataMaterialSelector<T>( model.getInterfaceMesh().getData<T>(name), model, first_index) {} }; } // akantu #endif // __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_event_handler.hh b/src/model/solid_mechanics/solid_mechanics_model_event_handler.hh index ff5d8538c..6f1214c96 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_event_handler.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_event_handler.hh @@ -1,127 +1,126 @@ /** * @file solid_mechanics_model_event_handler.hh * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Dec 18 2015 + * @date last modification: Wed Nov 08 2017 * * @brief EventHandler implementation for SolidMechanicsEvents * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_EVENT_HANDLER_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_EVENT_HANDLER_HH__ namespace akantu { /// akantu::SolidMechanicsModelEvent is the base event for model namespace SolidMechanicsModelEvent { struct BeforeSolveStepEvent { BeforeSolveStepEvent(AnalysisMethod & method) : method(method) {} AnalysisMethod method; }; struct AfterSolveStepEvent { AfterSolveStepEvent(AnalysisMethod & method) : method(method) {} AnalysisMethod method; }; struct BeforeDumpEvent { BeforeDumpEvent() = default; }; struct BeginningOfDamageIterationEvent { BeginningOfDamageIterationEvent() = default; }; struct AfterDamageEvent { AfterDamageEvent() = default; }; } /// akantu::SolidMechanicsModelEvent class SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: virtual ~SolidMechanicsModelEventHandler() = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// Send what is before the solve step to the beginning of solve step through /// EventManager inline void sendEvent(const SolidMechanicsModelEvent::BeforeSolveStepEvent & event) { onBeginningSolveStep(event.method); } /// Send what is after the solve step to the end of solve step through /// EventManager inline void sendEvent(const SolidMechanicsModelEvent::AfterSolveStepEvent & event) { onEndSolveStep(event.method); } /// Send what is before dump to current dump through EventManager inline void sendEvent(__attribute__((unused)) const SolidMechanicsModelEvent::BeforeDumpEvent & event) { onDump(); } /// Send what is at the beginning of damage iteration to Damage iteration /// through EventManager inline void sendEvent( __attribute__((unused)) const SolidMechanicsModelEvent::BeginningOfDamageIterationEvent & event) { onDamageIteration(); } /// Send what is after damage for the damage update through EventManager inline void sendEvent(__attribute__((unused)) const SolidMechanicsModelEvent::AfterDamageEvent & event) { onDamageUpdate(); } template <class EventHandler> friend class EventHandlerManager; /* ------------------------------------------------------------------------ */ /* Interface */ /* ------------------------------------------------------------------------ */ public: /// function to implement to react on akantu::BeforeSolveStepEvent virtual void onBeginningSolveStep(__attribute__((unused)) const AnalysisMethod & method) {} /// function to implement to react on akantu::AfterSolveStepEvent virtual void onEndSolveStep(__attribute__((unused)) const AnalysisMethod & method) {} /// function to implement to react on akantu::BeforeDumpEvent virtual void onDump() {} /// function to implement to react on akantu::BeginningOfDamageIterationEvent virtual void onDamageIteration() {} /// function to implement to react on akantu::AfterDamageEvent virtual void onDamageUpdate() {} }; } // akantu #endif /* __AKANTU_SOLID_MECHANICS_MODEL_EVENT_HANDLER_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc index 322a480da..1ae4784cc 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc @@ -1,102 +1,102 @@ /** * @file solid_mechanics_model_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 04 2010 - * @date last modification: Wed Nov 18 2015 + * @date last modification: Tue Dec 05 2017 * * @brief Implementation of the inline functions of the SolidMechanicsModel * 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_named_argument.hh" #include "material_selector.hh" #include "material_selector_tmpl.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_INLINE_IMPL_CC__ #define __AKANTU_SOLID_MECHANICS_MODEL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(UInt mat_index) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no " << mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(UInt mat_index) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no " << mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(const std::string & name) { AKANTU_DEBUG_IN(); std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named " << name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getMaterialIndex(const std::string & name) const { AKANTU_DEBUG_IN(); auto it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named " << name); AKANTU_DEBUG_OUT(); return it->second; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(const std::string & name) const { AKANTU_DEBUG_IN(); auto it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named " << name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_SOLID_MECHANICS_MODEL_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_io.cc b/src/model/solid_mechanics/solid_mechanics_model_io.cc index 71d9ff521..ba29a79ca 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_io.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_io.cc @@ -1,324 +1,326 @@ /** * @file solid_mechanics_model_io.cc * - * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Fri Jul 07 2017 + * @date creation: Sun Jul 09 2017 + * @date last modification: Sun Dec 03 2017 * - * @brief Dumpable part of the SolidMechnicsModel + * @brief Dumpable part of the SolidMechnicsModel * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" #include "group_manager_inline_impl.cc" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_element_partition.hh" #include "dumper_elemental_field.hh" #include "dumper_field.hh" #include "dumper_homogenizing_field.hh" #include "dumper_internal_material_field.hh" #include "dumper_iohelper.hh" #include "dumper_material_padders.hh" #include "dumper_paraview.hh" #endif namespace akantu { /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::isInternal(const std::string & field_name, const ElementKind & element_kind) { /// check if at least one material contains field_id as an internal for (auto & material : materials) { bool is_internal = material->isInternal<Real>(field_name, element_kind); if (is_internal) return true; } return false; } /* -------------------------------------------------------------------------- */ ElementTypeMap<UInt> SolidMechanicsModel::getInternalDataPerElem(const std::string & field_name, const ElementKind & element_kind) { if (!(this->isInternal(field_name, element_kind))) AKANTU_EXCEPTION("unknown internal " << field_name); for (auto & material : materials) { if (material->isInternal<Real>(field_name, element_kind)) return material->getInternalDataPerElem<Real>(field_name, element_kind); } return ElementTypeMap<UInt>(); } /* -------------------------------------------------------------------------- */ ElementTypeMapArray<Real> & SolidMechanicsModel::flattenInternal(const std::string & field_name, const ElementKind & kind, const GhostType ghost_type) { std::pair<std::string, ElementKind> key(field_name, kind); if (this->registered_internals.count(key) == 0) { this->registered_internals[key] = new ElementTypeMapArray<Real>(field_name, this->id, this->memory_id); } ElementTypeMapArray<Real> * internal_flat = this->registered_internals[key]; for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, kind)) { if (internal_flat->exists(type, ghost_type)) { auto & internal = (*internal_flat)(type, ghost_type); // internal.clear(); internal.resize(0); } } for (auto & material : materials) { if (material->isInternal<Real>(field_name, kind)) material->flattenInternal(field_name, *internal_flat, ghost_type, kind); } return *internal_flat; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::flattenAllRegisteredInternals( const ElementKind & kind) { ElementKind _kind; ID _id; for (auto & internal : this->registered_internals) { std::tie(_id, _kind) = internal.first; if (kind == _kind) this->flattenInternal(_id, kind); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onDump() { this->flattenAllRegisteredInternals(_ek_regular); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * SolidMechanicsModel::createElementalField( const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & kind) { dumper::Field * field = nullptr; if (field_name == "partitions") field = mesh.createElementalField<UInt, dumper::ElementPartitionField>( mesh.getConnectivities(), group_name, spatial_dimension, kind); else if (field_name == "material_index") field = mesh.createElementalField<UInt, Vector, dumper::ElementalField>( material_index, group_name, spatial_dimension, kind); else { // this copy of field_name is used to compute derivated data such as // strain and von mises stress that are based on grad_u and stress std::string field_name_copy(field_name); if (field_name == "strain" || field_name == "Green strain" || field_name == "principal strain" || field_name == "principal Green strain") field_name_copy = "grad_u"; else if (field_name == "Von Mises stress") field_name_copy = "stress"; bool is_internal = this->isInternal(field_name_copy, kind); if (is_internal) { ElementTypeMap<UInt> nb_data_per_elem = this->getInternalDataPerElem(field_name_copy, kind); ElementTypeMapArray<Real> & internal_flat = this->flattenInternal(field_name_copy, kind); field = mesh.createElementalField<Real, dumper::InternalMaterialField>( internal_flat, group_name, spatial_dimension, kind, nb_data_per_elem); if (field_name == "strain") { auto * foo = new dumper::ComputeStrain<false>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "Von Mises stress") { auto * foo = new dumper::ComputeVonMisesStress(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "Green strain") { auto * foo = new dumper::ComputeStrain<true>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "principal strain") { auto * foo = new dumper::ComputePrincipalStrain<false>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "principal Green strain") { auto * foo = new dumper::ComputePrincipalStrain<true>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } // treat the paddings if (padding_flag) { if (field_name == "stress") { if (spatial_dimension == 2) { auto * foo = new dumper::StressPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } } else if (field_name == "strain" || field_name == "Green strain") { if (spatial_dimension == 2) { auto * foo = new dumper::StrainPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } } } // homogenize the field dumper::ComputeFunctorInterface * foo = dumper::HomogenizerProxy::createHomogenizer(*field); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } } return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string, Array<Real> *> real_nodal_fields; real_nodal_fields["displacement"] = this->displacement; real_nodal_fields["mass"] = this->mass; real_nodal_fields["velocity"] = this->velocity; real_nodal_fields["acceleration"] = this->acceleration; real_nodal_fields["external_force"] = this->external_force; real_nodal_fields["internal_force"] = this->internal_force; real_nodal_fields["increment"] = this->displacement_increment; if (field_name == "force") { AKANTU_EXCEPTION("The 'force' field has been renamed in 'external_force'"); } else if (field_name == "residual") { AKANTU_EXCEPTION( "The 'residual' field has been replaced by 'internal_force'"); } dumper::Field * field = nullptr; if (padding_flag) field = this->mesh.createNodalField(real_nodal_fields[field_name], group_name, 3); else field = this->mesh.createNodalField(real_nodal_fields[field_name], group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool( const std::string & field_name, const std::string & group_name, __attribute__((unused)) bool padding_flag) { std::map<std::string, Array<bool> *> uint_nodal_fields; uint_nodal_fields["blocked_dofs"] = blocked_dofs; dumper::Field * field = nullptr; field = mesh.createNodalField(uint_nodal_fields[field_name], group_name); return field; } /* -------------------------------------------------------------------------- */ #else /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createElementalField(const std::string &, const std::string &, bool, const UInt &, const ElementKind &) { return nullptr; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string &, const std::string &, bool) { return nullptr; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string &, const std::string &, bool) { return nullptr; } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump() { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(time, step); } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_mass.cc b/src/model/solid_mechanics/solid_mechanics_model_mass.cc index e0f5392a6..66ddd6ac6 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_mass.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_mass.cc @@ -1,159 +1,158 @@ /** * @file solid_mechanics_model_mass.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Oct 05 2010 - * @date last modification: Fri Oct 16 2015 + * @date last modification: Wed Nov 08 2017 * * @brief function handling mass computation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integrator_gauss.hh" #include "material.hh" #include "model_solver.hh" #include "shape_lagrange.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class ComputeRhoFunctor { public: explicit ComputeRhoFunctor(const SolidMechanicsModel & model) : model(model){}; void operator()(Matrix<Real> & rho, const Element & element) const { const Array<UInt> & mat_indexes = model.getMaterialByElement(element.type, element.ghost_type); Real mat_rho = model.getMaterial(mat_indexes(element.element)).getParam("rho"); rho.set(mat_rho); } private: const SolidMechanicsModel & model; }; /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMassLumped() { AKANTU_DEBUG_IN(); if (not need_to_reassemble_lumped_mass) return; UInt nb_nodes = mesh.getNbNodes(); if (this->mass == nullptr) { std::stringstream sstr_mass; sstr_mass << id << ":mass"; mass = &(alloc<Real>(sstr_mass.str(), nb_nodes, Model::spatial_dimension, 0)); } else { mass->clear(); } if (!this->getDOFManager().hasLumpedMatrix("M")) { this->getDOFManager().getNewLumpedMatrix("M"); } this->getDOFManager().clearLumpedMatrix("M"); assembleMassLumped(_not_ghost); assembleMassLumped(_ghost); this->getDOFManager().getLumpedMatrixPerDOFs("displacement", "M", *(this->mass)); /// for not connected nodes put mass to one in order to avoid #if !defined(AKANTU_NDEBUG) bool has_unconnected_nodes = false; auto mass_it = mass->begin_reinterpret(mass->size() * mass->getNbComponent()); auto mass_end = mass->end_reinterpret(mass->size() * mass->getNbComponent()); for (; mass_it != mass_end; ++mass_it) { if (std::abs(*mass_it) < std::numeric_limits<Real>::epsilon() || Math::isnan(*mass_it)) { has_unconnected_nodes = true; break; } } if (has_unconnected_nodes) AKANTU_DEBUG_WARNING("There are nodes that seem to not be connected to any " "elements, beware that they have lumped mass of 0."); #endif this->synchronize(_gst_smm_mass); need_to_reassemble_lumped_mass = false; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMass() { AKANTU_DEBUG_IN(); if (not need_to_reassemble_mass) return; this->getDOFManager().clearMatrix("M"); assembleMass(_not_ghost); need_to_reassemble_mass = false; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMassLumped(GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem = getFEEngineClass<MyFEEngineType>(); ComputeRhoFunctor compute_rho(*this); for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type)) { fem.assembleFieldLumped(compute_rho, "M", "displacement", this->getDOFManager(), type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMass(GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem = getFEEngineClass<MyFEEngineType>(); ComputeRhoFunctor compute_rho(*this); for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type)) { fem.assembleFieldMatrix(compute_rho, "M", "displacement", this->getDOFManager(), type, ghost_type); } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_material.cc b/src/model/solid_mechanics/solid_mechanics_model_material.cc index 74ce922a9..d21eb55e3 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_material.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_material.cc @@ -1,254 +1,253 @@ /** * @file solid_mechanics_model_material.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Nov 26 2010 - * @date last modification: Mon Nov 16 2015 + * @date last modification: Tue Feb 20 2018 * * @brief instatiation of materials * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "aka_math.hh" #include "material_non_local.hh" #include "mesh_iterators.hh" #include "non_local_manager.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material & SolidMechanicsModel::registerNewMaterial(const ParserSection & section) { std::string mat_name; std::string mat_type = section.getName(); std::string opt_param = section.getOption(); try { std::string tmp = section.getParameter("name"); mat_name = tmp; /** this can seam weird, but there is an ambiguous operator * overload that i couldn't solve. @todo remove the * weirdness of this code */ } catch (debug::Exception &) { AKANTU_ERROR("A material of type \'" << mat_type << "\' in the input file has been defined without a name!"); } Material & mat = this->registerNewMaterial(mat_name, mat_type, opt_param); mat.parseSection(section); return mat; } /* -------------------------------------------------------------------------- */ Material & SolidMechanicsModel::registerNewMaterial(const ID & mat_name, const ID & mat_type, const ID & opt_param) { AKANTU_DEBUG_ASSERT(materials_names_to_id.find(mat_name) == materials_names_to_id.end(), "A material with this name '" << mat_name << "' has already been registered. " << "Please use unique names for materials"); UInt mat_count = materials.size(); materials_names_to_id[mat_name] = mat_count; std::stringstream sstr_mat; sstr_mat << this->id << ":" << mat_count << ":" << mat_type; ID mat_id = sstr_mat.str(); std::unique_ptr<Material> material = MaterialFactory::getInstance().allocate( mat_type, spatial_dimension, opt_param, *this, mat_id); materials.push_back(std::move(material)); return *(materials.back()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::instantiateMaterials() { ParserSection model_section; bool is_empty; std::tie(model_section, is_empty) = this->getParserSection(); if (not is_empty) { auto model_materials = model_section.getSubSections(ParserType::_material); for (const auto & section : model_materials) { this->registerNewMaterial(section); } } auto sub_sections = this->parser.getSubSections(ParserType::_material); for (const auto & section : sub_sections) { this->registerNewMaterial(section); } #ifdef AKANTU_DAMAGE_NON_LOCAL for (auto & material : materials) { if (dynamic_cast<MaterialNonLocalInterface *>(material.get()) == nullptr) continue; this->non_local_manager = std::make_unique<NonLocalManager>( *this, *this, id + ":non_local_manager", memory_id); break; } #endif if (materials.empty()) AKANTU_EXCEPTION("No materials where instantiated for the model" << getID()); are_materials_instantiated = true; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assignMaterialToElements( const ElementTypeMapArray<UInt> * filter) { for_each_element( mesh, [&](auto && element) { UInt mat_index = (*material_selector)(element); AKANTU_DEBUG_ASSERT( mat_index < materials.size(), "The material selector returned an index that does not exists"); material_index(element) = mat_index; }, _element_filter = filter, _ghost_type = _not_ghost); if (non_local_manager) non_local_manager->synchronize(*this, _gst_material_id); for_each_element(mesh, [&](auto && element) { auto mat_index = material_index(element); auto index = materials[mat_index]->addElement(element); material_local_numbering(element) = index; }, _element_filter = filter, _ghost_type = _not_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initMaterials() { AKANTU_DEBUG_ASSERT(materials.size() != 0, "No material to initialize !"); if (!are_materials_instantiated) instantiateMaterials(); this->assignMaterialToElements(); // synchronize the element material arrays this->synchronize(_gst_material_id); for (auto & material : materials) { /// init internals properties material->initMaterial(); } this->synchronize(_gst_smm_init_mat); if (this->non_local_manager) { this->non_local_manager->initialize(); } } /* -------------------------------------------------------------------------- */ Int SolidMechanicsModel::getInternalIndexFromID(const ID & id) const { AKANTU_DEBUG_IN(); auto it = materials.begin(); auto end = materials.end(); for (; it != end; ++it) if ((*it)->getID() == id) { AKANTU_DEBUG_OUT(); return (it - materials.begin()); } AKANTU_DEBUG_OUT(); return -1; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::reassignMaterial() { AKANTU_DEBUG_IN(); std::vector<Array<Element>> element_to_add(materials.size()); std::vector<Array<Element>> element_to_remove(materials.size()); Element element; for (auto ghost_type : ghost_types) { element.ghost_type = ghost_type; for (auto type : mesh.elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array<UInt> & mat_indexes = material_index(type, ghost_type); for (UInt el = 0; el < nb_element; ++el) { element.element = el; UInt old_material = mat_indexes(el); UInt new_material = (*material_selector)(element); if (old_material != new_material) { element_to_add[new_material].push_back(element); element_to_remove[old_material].push_back(element); } } } } UInt mat_index = 0; for (auto mat_it = materials.begin(); mat_it != materials.end(); ++mat_it, ++mat_index) { (*mat_it)->removeElements(element_to_remove[mat_index]); (*mat_it)->addElements(element_to_add[mat_index]); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::applyEigenGradU( const Matrix<Real> & prescribed_eigen_grad_u, const ID & material_name, const GhostType ghost_type) { AKANTU_DEBUG_ASSERT(prescribed_eigen_grad_u.size() == spatial_dimension * spatial_dimension, "The prescribed grad_u is not of the good size"); for (auto & material : materials) { if (material->getName() == material_name) material->applyEigenGradU(prescribed_eigen_grad_u, ghost_type); } } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_tmpl.hh b/src/model/solid_mechanics/solid_mechanics_model_tmpl.hh index afb0de79a..c749da2dd 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_tmpl.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_tmpl.hh @@ -1,62 +1,62 @@ /** * @file solid_mechanics_model_tmpl.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Nov 13 2015 + * @date last modification: Tue Nov 07 2017 * * @brief template part of solid mechanics model * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "material.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_TMPL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_TMPL_HH__ namespace akantu { #define FWD(...) ::std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__) /* -------------------------------------------------------------------------- */ template <typename Operation> void SolidMechanicsModel::splitByMaterial(const Array<Element> & elements, Operation && op) const { std::vector<Array<Element>> elements_per_mat(materials.size()); this->splitElementByMaterial(elements, elements_per_mat); for (auto && mat : zip(materials, elements_per_mat)) { FWD(op)(FWD(*std::get<0>(mat)), FWD(std::get<1>(mat))); } } #undef FWD /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_SOLID_MECHANICS_MODEL_TMPL_HH__ */ diff --git a/src/model/solver_callback.cc b/src/model/solver_callback.cc index 82b50e404..92728eb9d 100644 --- a/src/model/solver_callback.cc +++ b/src/model/solver_callback.cc @@ -1,53 +1,54 @@ /** * @file solver_callback.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Mar 2 12:47:17 2016 + * @date creation: Tue Jul 20 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Default behavior of solver_callbacks * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solver_callback.hh" #include "dof_manager.hh" namespace akantu { /* -------------------------------------------------------------------------- */ SolverCallback::SolverCallback(DOFManager & dof_manager) : sc_dof_manager(&dof_manager) {} /* -------------------------------------------------------------------------- */ SolverCallback::SolverCallback() = default; /* -------------------------------------------------------------------------- */ SolverCallback::~SolverCallback() = default; /* -------------------------------------------------------------------------- */ void SolverCallback::setDOFManager(DOFManager & dof_manager) { this->sc_dof_manager = &dof_manager; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solver_callback.hh b/src/model/solver_callback.hh index f986d9908..c282dcec2 100644 --- a/src/model/solver_callback.hh +++ b/src/model/solver_callback.hh @@ -1,108 +1,109 @@ /** * @file solver_callback.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Sep 15 22:45:27 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Feb 21 2018 * * @brief Class defining the interface for non_linear_solver callbacks * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLVER_CALLBACK_HH__ #define __AKANTU_SOLVER_CALLBACK_HH__ namespace akantu { class DOFManager; } namespace akantu { class SolverCallback { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit SolverCallback(DOFManager & dof_manager); explicit SolverCallback(); /* ------------------------------------------------------------------------ */ virtual ~SolverCallback(); protected: void setDOFManager(DOFManager & dof_manager); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get the type of matrix needed virtual MatrixType getMatrixType(const ID &) = 0; /// callback to assemble a Matrix virtual void assembleMatrix(const ID &) = 0; /// callback to assemble a lumped Matrix virtual void assembleLumpedMatrix(const ID &) = 0; /// callback to assemble the residual (rhs) virtual void assembleResidual() = 0; /// callback to assemble the rhs parts, (e.g. internal_forces + /// external_forces) virtual void assembleResidual(const ID & /*residual_part*/) {} /* ------------------------------------------------------------------------ */ /* Dynamic simulations part */ /* ------------------------------------------------------------------------ */ /// callback for the predictor (in case of dynamic simulation) virtual void predictor() {} /// callback for the corrector (in case of dynamic simulation) virtual void corrector() {} /// tells if the residual can be computed in separated parts virtual bool canSplitResidual() { return false; } /* ------------------------------------------------------------------------ */ /* management callbacks */ /* ------------------------------------------------------------------------ */ virtual void beforeSolveStep(){}; virtual void afterSolveStep(){}; protected: /// DOFManager prefixed to avoid collision in multiple inheritance cases DOFManager * sc_dof_manager{nullptr}; }; namespace debug { class SolverCallbackResidualPartUnknown : public Exception { public: SolverCallbackResidualPartUnknown(const ID & residual_part) : Exception(residual_part + " is not known here.") {} }; } } // namespace akantu #endif /* __AKANTU_SOLVER_CALLBACK_HH__ */ diff --git a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_2.hh b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_2.hh index d59f608e5..53300ae7e 100644 --- a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_2.hh +++ b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_2.hh @@ -1,134 +1,137 @@ /** * @file structural_element_bernoulli_beam_2.hh * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Tue Sep 19 2017 + * @date creation: Wed Oct 11 2017 + * @date last modification: Wed Jan 10 2018 * - * @brief Specific functions for bernoulli beam 2d + * @brief Specific functions for bernoulli beam 2d * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "structural_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_2_HH__ #define __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_2_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <> inline void StructuralMechanicsModel::assembleMass<_bernoulli_beam_2>() { AKANTU_DEBUG_IN(); constexpr ElementType type = _bernoulli_beam_2; auto & fem = getFEEngineClass<MyFEEngineType>(); auto nb_element = mesh.getNbElement(type); auto nb_nodes_per_element = mesh.getNbNodesPerElement(type); auto nb_quadrature_points = fem.getNbIntegrationPoints(type); auto nb_fields_to_interpolate = ElementClass<type>::getNbStressComponents(); auto nt_n_field_size = nb_degree_of_freedom * nb_nodes_per_element; Array<Real> n(nb_element * nb_quadrature_points, nb_fields_to_interpolate * nt_n_field_size, "N"); Array<Real> * rho_field = new Array<Real>(nb_element * nb_quadrature_points, 1, "Rho"); rho_field->clear(); computeRho(*rho_field, type, _not_ghost); #if 0 bool sign = true; for (auto && ghost_type : ghost_types) { fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 0, 0, 0, sign, ghost_type); // Ni ui -> u fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 1, 1, 1, sign, ghost_type); // Mi vi -> v fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 2, 2, 1, sign, ghost_type); // Li Theta_i -> v fem.assembleFieldMatrix(*rho_field, nb_degree_of_freedom, *mass_matrix, n, rotation_matrix, type, ghost_type); } #endif delete rho_field; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeRotationMatrix<_bernoulli_beam_2>( Array<Real> & rotations) { auto type = _bernoulli_beam_2; auto nodes_it = mesh.getNodes().begin(this->spatial_dimension); for (auto && tuple : zip(make_view(mesh.getConnectivity(type), 2), make_view(rotations, nb_degree_of_freedom, nb_degree_of_freedom))) { auto & connec = std::get<0>(tuple); auto & R = std::get<1>(tuple); Vector<Real> x2 = nodes_it[connec(1)]; // X2 Vector<Real> x1 = nodes_it[connec(0)]; // X1 auto le = x1.distance(x2); auto c = (x2(0) - x1(0)) / le; auto s = (x2(1) - x1(1)) / le; /// Definition of the rotation matrix R = {{c, s, 0.}, {-s, c, 0.}, {0., 0., 1.}}; } } /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_2>( Array<Real> & tangent_moduli) { // auto nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_2); auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(_bernoulli_beam_2); auto tangent_size = 2; tangent_moduli.clear(); auto D_it = tangent_moduli.begin(tangent_size, tangent_size); auto el_mat = element_material(_bernoulli_beam_2, _not_ghost).begin(); for (auto & mat : element_material(_bernoulli_beam_2, _not_ghost)) { auto E = materials[mat].E; auto A = materials[mat].A; auto I = materials[mat].I; for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { auto & D = *D_it; D(0, 0) = E * A; D(1, 1) = E * I; } } } } // namespace akantu #endif /* __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_2_HH__ */ diff --git a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh index 16616689c..b00cbd1cd 100644 --- a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh +++ b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh @@ -1,187 +1,190 @@ /** * @file structural_element_bernoulli_beam_3.hh * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * - * @date creation Tue Sep 19 2017 + * @date creation: Wed Oct 11 2017 + * @date last modification: Tue Feb 20 2018 * - * @brief Specific functions for bernoulli beam 3d + * @brief Specific functions for bernoulli beam 3d * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH__ #define __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH__ #include "structural_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <> inline void StructuralMechanicsModel::assembleMass<_bernoulli_beam_3>() { AKANTU_DEBUG_IN(); #if 0 GhostType ghost_type = _not_ghost; ElementType type = _bernoulli_beam_3; MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); UInt nb_element = getFEEngine().getMesh().getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); UInt nb_fields_to_interpolate = getTangentStiffnessVoigtSize<_bernoulli_beam_3>(); UInt nt_n_field_size = nb_degree_of_freedom * nb_nodes_per_element; Array<Real> * n = new Array<Real>(nb_element * nb_quadrature_points, nb_fields_to_interpolate * nt_n_field_size, "N"); n->clear(); Array<Real> * rho_field = new Array<Real>(nb_element * nb_quadrature_points, "Rho"); rho_field->clear(); computeRho(*rho_field, type, _not_ghost); /* -------------------------------------------------------------------------- */ fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 0, 0, 0, true, ghost_type); // Ni ui -> u fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 1, 1, 1, true, ghost_type); // Mi vi -> v fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 2, 5, 1, true, ghost_type); // Li Theta_z_i -> v fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 1, 2, 2, true, ghost_type); // Mi wi -> w fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 2, 4, 2, false, ghost_type); // -Li Theta_y_i -> w fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 0, 3, 3, true, ghost_type); // Ni Theta_x_i->Theta_x /* -------------------------------------------------------------------------- */ fem.assembleFieldMatrix(*rho_field, nb_degree_of_freedom, *mass_matrix, n, rotation_matrix, type, ghost_type); delete n; delete rho_field; #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeRotationMatrix<_bernoulli_beam_3>( Array<Real> & rotations) { ElementType type = _bernoulli_beam_3; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); auto n_it = mesh.getNormals(type).begin(spatial_dimension); Array<UInt>::iterator<Vector<UInt>> connec_it = mesh.getConnectivity(type).begin(2); auto nodes_it = mesh.getNodes().begin(spatial_dimension); Matrix<Real> Pe(spatial_dimension, spatial_dimension); Matrix<Real> Pg(spatial_dimension, spatial_dimension); Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension); Vector<Real> x_n(spatial_dimension); // x vect n Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e = 0; e < nb_element; ++e, ++n_it, ++connec_it, ++R_it) { Vector<Real> & n = *n_it; Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x; x = nodes_it[connec(1)]; // X2 Vector<Real> y; y = nodes_it[connec(0)]; // X1 Real l = x.distance(y); x -= y; // X2 - X1 x_n.crossProduct(x, n); Pe.eye(); Pe(0, 0) *= l; Pe(1, 1) *= -l; Pg(0, 0) = x(0); Pg(0, 1) = x_n(0); Pg(0, 2) = n(0); Pg(1, 0) = x(1); Pg(1, 1) = x_n(1); Pg(1, 2) = n(1); Pg(2, 0) = x(2); Pg(2, 1) = x_n(2); Pg(2, 2) = n(2); inv_Pg.inverse(Pg); Pe *= inv_Pg; for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { R(i, j) = Pe(i, j); R(i + spatial_dimension, j + spatial_dimension) = Pe(i, j); } } } } /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_3>( Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(_bernoulli_beam_3); UInt tangent_size = 4; tangent_moduli.clear(); Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); for (UInt e = 0; e < nb_element; ++e) { UInt mat = element_material(_bernoulli_beam_3, _not_ghost)(e); Real E = materials[mat].E; Real A = materials[mat].A; Real Iz = materials[mat].Iz; Real Iy = materials[mat].Iy; Real GJ = materials[mat].GJ; for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0, 0) = E * A; D(1, 1) = E * Iz; D(2, 2) = E * Iy; D(3, 3) = GJ; } } } } // akantu #endif /* __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH__ */ diff --git a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh index 30a4d44b4..e5559a345 100644 --- a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh +++ b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh @@ -1,77 +1,80 @@ /** - * @file structural_element_bernoulli_kirchhoff_shell.hh + * @file structural_element_kirchhoff_shell.hh * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * - * @date creation Tue Sep 19 2017 + * @date creation: Wed Oct 11 2017 + * @date last modification: Wed Feb 21 2018 * - * @brief Specific functions for bernoulli kirchhoff shell + * @brief Specific functions for bernoulli kirchhoff shell * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__ #define __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__ #include "structural_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <> inline void StructuralMechanicsModel::assembleMass<_discrete_kirchhoff_triangle_18>() { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeTangentModuli< _discrete_kirchhoff_triangle_18>(Array<Real> & tangent_moduli) { auto tangent_size = ElementClass<_discrete_kirchhoff_triangle_18>::getNbStressComponents(); auto nb_quad = getFEEngine().getNbIntegrationPoints(_discrete_kirchhoff_triangle_18); auto H_it = tangent_moduli.begin(tangent_size, tangent_size); for (UInt mat : element_material(_discrete_kirchhoff_triangle_18, _not_ghost)) { auto & m = materials[mat]; for (UInt q = 0; q < nb_quad; ++q, ++H_it) { auto & H = *H_it; H.clear(); Matrix<Real> D = {{1, m.nu, 0}, {m.nu, 1, 0}, {0, 0, (1 - m.nu) / 2}}; D *= m.E * m.t / (1 - m.nu * m.nu); H.block(D, 0, 0); // in plane membrane behavior H.block(D * Math::pow<3>(m.t) / 12., 3, 3); // bending behavior } } } } // akantu #endif /* __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_DISCRETE_KIRCHHOFF_TRIANGLE_18_HH__ \ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc index f1ea3fff0..29392c28c 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.cc +++ b/src/model/structural_mechanics/structural_mechanics_model.cc @@ -1,483 +1,483 @@ /** * @file structural_mechanics_model.cc * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Model implementation for StucturalMechanics elements * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model.hh" #include "dof_manager.hh" #include "integrator_gauss.hh" #include "mesh.hh" #include "shape_structural.hh" #include "sparse_matrix.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumpable_inline_impl.hh" #include "dumper_elemental_field.hh" #include "dumper_iohelper_paraview.hh" #include "group_manager_inline_impl.cc" #endif /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model_inline_impl.cc" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::StructuralMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, ModelType::_structural_mechanics_model, dim, id, memory_id), time_step(NAN), f_m2a(1.0), stress("stress", id, memory_id), element_material("element_material", id, memory_id), set_ID("beam sets", id, memory_id), rotation_matrix("rotation_matices", id, memory_id) { AKANTU_DEBUG_IN(); registerFEEngineObject<MyFEEngineType>("StructuralMechanicsFEEngine", mesh, spatial_dimension); if (spatial_dimension == 2) nb_degree_of_freedom = 3; else if (spatial_dimension == 3) nb_degree_of_freedom = 6; else { AKANTU_TO_IMPLEMENT(); } #ifdef AKANTU_USE_IOHELPER this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); #endif this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_structural); this->initDOFManager(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::~StructuralMechanicsModel() = default; /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initFullImpl(const ModelOptions & options) { // <<<< This is the SolidMechanicsModel implementation for future ref >>>> // material_index.initialize(mesh, _element_kind = _ek_not_defined, // _default_value = UInt(-1), _with_nb_element = // true); // material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined, // _with_nb_element = true); // Model::initFullImpl(options); // // initialize pbc // if (this->pbc_pair.size() != 0) // this->initPBC(); // // initialize the materials // if (this->parser.getLastParsedFile() != "") { // this->instantiateMaterials(); // } // this->initMaterials(); // this->initBC(*this, *displacement, *displacement_increment, // *external_force); // <<<< END >>>> Model::initFullImpl(options); // Initializing stresses ElementTypeMap<UInt> stress_components; /// TODO this is ugly af, maybe add a function to FEEngine for (auto & type : mesh.elementTypes(_spatial_dimension = _all_dimensions, _element_kind = _ek_structural)) { UInt nb_components = 0; // Getting number of components for each element type #define GET_(type) nb_components = ElementClass<type>::getNbStressComponents() AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(GET_); #undef GET_ stress_components(nb_components, type); } stress.initialize(getFEEngine(), _spatial_dimension = _all_dimensions, _element_kind = _ek_structural, _all_ghost_types = true, _nb_component = [&stress_components]( const ElementType & type, const GhostType &) -> UInt { return stress_components(type); }); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initFEEngineBoundary() { /// TODO: this function should not be reimplemented /// we're just avoiding a call to Model::initFEEngineBoundary() } /* -------------------------------------------------------------------------- */ // void StructuralMechanicsModel::setTimeStep(Real time_step) { // this->time_step = time_step; // #if defined(AKANTU_USE_IOHELPER) // this->mesh.getDumper().setTimeStep(time_step); // #endif // } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initSolver( TimeStepSolverType time_step_solver_type, NonLinearSolverType) { AKANTU_DEBUG_IN(); this->allocNodalField(displacement_rotation, nb_degree_of_freedom, "displacement"); this->allocNodalField(external_force, nb_degree_of_freedom, "external_force"); this->allocNodalField(internal_force, nb_degree_of_freedom, "internal_force"); this->allocNodalField(blocked_dofs, nb_degree_of_freedom, "blocked_dofs"); auto & dof_manager = this->getDOFManager(); if (!dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *displacement_rotation, _dst_nodal); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); } if (time_step_solver_type == _tsst_dynamic || time_step_solver_type == _tsst_dynamic_lumped) { this->allocNodalField(velocity, spatial_dimension, "velocity"); this->allocNodalField(acceleration, spatial_dimension, "acceleration"); if (!dof_manager.hasDOFsDerivatives("displacement", 1)) { dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity); dof_manager.registerDOFsDerivative("displacement", 2, *this->acceleration); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initModel() { for (auto && type : mesh.elementTypes(_element_kind = _ek_structural)) { // computeRotationMatrix(type); element_material.alloc(mesh.getNbElement(type), 1, type); } getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); getDOFManager().getMatrix("K").clear(); for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { #define ASSEMBLE_STIFFNESS_MATRIX(type) assembleStiffnessMatrix<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(ASSEMBLE_STIFFNESS_MATRIX); #undef ASSEMBLE_STIFFNESS_MATRIX } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeStresses() { AKANTU_DEBUG_IN(); for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { #define COMPUTE_STRESS_ON_QUAD(type) computeStressOnQuad<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_STRESS_ON_QUAD); #undef COMPUTE_STRESS_ON_QUAD } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeRotationMatrix(const ElementType & type) { Mesh & mesh = getFEEngine().getMesh(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); if (!rotation_matrix.exists(type)) { rotation_matrix.alloc(nb_element, nb_degree_of_freedom * nb_nodes_per_element * nb_degree_of_freedom * nb_nodes_per_element, type); } else { rotation_matrix(type).resize(nb_element); } rotation_matrix(type).clear(); Array<Real> rotations(nb_element, nb_degree_of_freedom * nb_degree_of_freedom); rotations.clear(); #define COMPUTE_ROTATION_MATRIX(type) computeRotationMatrix<type>(rotations); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_ROTATION_MATRIX); #undef COMPUTE_ROTATION_MATRIX auto R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); auto T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++R_it, ++T_it) { auto & T = *T_it; auto & R = *R_it; for (UInt k = 0; k < nb_nodes_per_element; ++k) { for (UInt i = 0; i < nb_degree_of_freedom; ++i) for (UInt j = 0; j < nb_degree_of_freedom; ++j) T(k * nb_degree_of_freedom + i, k * nb_degree_of_freedom + j) = R(i, j); } } } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel::createNodalFieldBool( const std::string & field_name, const std::string & group_name, __attribute__((unused)) bool padding_flag) { std::map<std::string, Array<bool> *> uint_nodal_fields; uint_nodal_fields["blocked_dofs"] = blocked_dofs; dumper::Field * field = NULL; field = mesh.createNodalField(uint_nodal_fields[field_name], group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { UInt n; if (spatial_dimension == 2) { n = 2; } else { n = 3; } if (field_name == "displacement") { return mesh.createStridedNodalField(displacement_rotation, group_name, n, 0, padding_flag); } if (field_name == "rotation") { return mesh.createStridedNodalField(displacement_rotation, group_name, nb_degree_of_freedom - n, n, padding_flag); } if (field_name == "force") { return mesh.createStridedNodalField(external_force, group_name, n, 0, padding_flag); } if (field_name == "momentum") { return mesh.createStridedNodalField( external_force, group_name, nb_degree_of_freedom - n, n, padding_flag); } if (field_name == "internal_force") { return mesh.createStridedNodalField(internal_force, group_name, n, 0, padding_flag); } if (field_name == "internal_momentum") { return mesh.createStridedNodalField( internal_force, group_name, nb_degree_of_freedom - n, n, padding_flag); } return nullptr; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel::createElementalField( const std::string & field_name, const std::string & group_name, bool, const ElementKind & kind, const std::string &) { dumper::Field * field = NULL; if (field_name == "element_index_by_material") field = mesh.createElementalField<UInt, Vector, dumper::ElementalField>( field_name, group_name, this->spatial_dimension, kind); return field; } /* -------------------------------------------------------------------------- */ /* Virtual methods from SolverCallback */ /* -------------------------------------------------------------------------- */ /// get the type of matrix needed MatrixType StructuralMechanicsModel::getMatrixType(const ID & /*id*/) { return _symmetric; } /// callback to assemble a Matrix void StructuralMechanicsModel::assembleMatrix(const ID & id) { if (id == "K") assembleStiffnessMatrix(); } /// callback to assemble a lumped Matrix void StructuralMechanicsModel::assembleLumpedMatrix(const ID & /*id*/) {} /// callback to assemble the residual StructuralMechanicsModel::(rhs) void StructuralMechanicsModel::assembleResidual() { AKANTU_DEBUG_IN(); auto & dof_manager = getDOFManager(); internal_force->clear(); computeStresses(); assembleInternalForce(); dof_manager.assembleToResidual("displacement", *internal_force, -1); dof_manager.assembleToResidual("displacement", *external_force, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Virtual methods from MeshEventHandler */ /* -------------------------------------------------------------------------- */ /// function to implement to react on akantu::NewNodesEvent void StructuralMechanicsModel::onNodesAdded(const Array<UInt> & /*nodes_list*/, const NewNodesEvent & /*event*/) {} /// function to implement to react on akantu::RemovedNodesEvent void StructuralMechanicsModel::onNodesRemoved( const Array<UInt> & /*nodes_list*/, const Array<UInt> & /*new_numbering*/, const RemovedNodesEvent & /*event*/) {} /// function to implement to react on akantu::NewElementsEvent void StructuralMechanicsModel::onElementsAdded( const Array<Element> & /*elements_list*/, const NewElementsEvent & /*event*/) {} /// function to implement to react on akantu::RemovedElementsEvent void StructuralMechanicsModel::onElementsRemoved( const Array<Element> & /*elements_list*/, const ElementTypeMapArray<UInt> & /*new_numbering*/, const RemovedElementsEvent & /*event*/) {} /// function to implement to react on akantu::ChangedElementsEvent void StructuralMechanicsModel::onElementsChanged( const Array<Element> & /*old_elements_list*/, const Array<Element> & /*new_elements_list*/, const ElementTypeMapArray<UInt> & /*new_numbering*/, const ChangedElementsEvent & /*event*/) {} /* -------------------------------------------------------------------------- */ /* Virtual methods from Model */ /* -------------------------------------------------------------------------- */ /// get some default values for derived classes std::tuple<ID, TimeStepSolverType> StructuralMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _static: { return std::make_tuple("static", _tsst_static); } case _implicit_dynamic: { return std::make_tuple("implicit", _tsst_dynamic); } default: return std::make_tuple("unknown", _tsst_not_defined); } } /* ------------------------------------------------------------------------ */ ModelSolverOptions StructuralMechanicsModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_static: { options.non_linear_solver_type = _nls_linear; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleInternalForce() { for (auto type : mesh.elementTypes(_spatial_dimension = _all_dimensions, _element_kind = _ek_structural)) { assembleInternalForce(type, _not_ghost); // assembleInternalForce(type, _ghost); } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleInternalForce(const ElementType & type, GhostType gt) { auto & fem = getFEEngine(); auto & sigma = stress(type, gt); auto ndof = getNbDegreeOfFreedom(type); auto nb_nodes = mesh.getNbNodesPerElement(type); auto ndof_per_elem = ndof * nb_nodes; Array<Real> BtSigma(fem.getNbIntegrationPoints(type) * mesh.getNbElement(type), ndof_per_elem, "BtSigma"); fem.computeBtD(sigma, BtSigma, type, gt); Array<Real> intBtSigma(0, ndof_per_elem, "intBtSigma"); fem.integrate(BtSigma, intBtSigma, ndof_per_elem, type, gt); BtSigma.resize(0); getDOFManager().assembleElementalArrayLocalArray(intBtSigma, *internal_force, type, gt, 1); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/structural_mechanics/structural_mechanics_model.hh b/src/model/structural_mechanics/structural_mechanics_model.hh index baa53daa2..e0ef8f284 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.hh +++ b/src/model/structural_mechanics/structural_mechanics_model.hh @@ -1,332 +1,333 @@ /** * @file structural_mechanics_model.hh * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 - * @date last modification: Thu Jan 21 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Particular implementation of the structural elements in the * StructuralMechanicsModel * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_named_argument.hh" #include "boundary_condition.hh" #include "model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Material; class MaterialSelector; class DumperIOHelper; class NonLocalManager; template <ElementKind kind, class IntegrationOrderFunctor> class IntegratorGauss; template <ElementKind kind> class ShapeStructural; } // namespace akantu namespace akantu { struct StructuralMaterial { Real E{0}; Real A{1}; Real I{0}; Real Iz{0}; Real Iy{0}; Real GJ{0}; Real rho{0}; Real t{0}; Real nu{0}; }; class StructuralMechanicsModel : public Model { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using MyFEEngineType = FEEngineTemplate<IntegratorGauss, ShapeStructural, _ek_structural>; StructuralMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "structural_mechanics_model", const MemoryID & memory_id = 0); virtual ~StructuralMechanicsModel(); /// Init full model void initFullImpl(const ModelOptions & options) override; /// Init boundary FEEngine void initFEEngineBoundary() override; /* ------------------------------------------------------------------------ */ /* Virtual methods from SolverCallback */ /* ------------------------------------------------------------------------ */ /// get the type of matrix needed MatrixType getMatrixType(const ID &) override; /// callback to assemble a Matrix void assembleMatrix(const ID &) override; /// callback to assemble a lumped Matrix void assembleLumpedMatrix(const ID &) override; /// callback to assemble the residual (rhs) void assembleResidual() override; /* ------------------------------------------------------------------------ */ /* Virtual methods from MeshEventHandler */ /* ------------------------------------------------------------------------ */ /// function to implement to react on akantu::NewNodesEvent void onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) override; /// function to implement to react on akantu::RemovedNodesEvent void onNodesRemoved(const Array<UInt> & nodes_list, const Array<UInt> & new_numbering, const RemovedNodesEvent & event) override; /// function to implement to react on akantu::NewElementsEvent void onElementsAdded(const Array<Element> & elements_list, const NewElementsEvent & event) override; /// function to implement to react on akantu::RemovedElementsEvent void onElementsRemoved(const Array<Element> & elements_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; /// function to implement to react on akantu::ChangedElementsEvent void onElementsChanged(const Array<Element> & old_elements_list, const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> & new_numbering, const ChangedElementsEvent & event) override; /* ------------------------------------------------------------------------ */ /* Virtual methods from Model */ /* ------------------------------------------------------------------------ */ protected: /// get some default values for derived classes std::tuple<ID, TimeStepSolverType> getDefaultSolverID(const AnalysisMethod & method) override; ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const override; UInt getNbDegreeOfFreedom(const ElementType & type) const; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ void initSolver(TimeStepSolverType, NonLinearSolverType) override; /// initialize the model void initModel() override; /// compute the stresses per elements void computeStresses(); /// compute the nodal forces void assembleInternalForce(); /// compute the nodal forces for an element type void assembleInternalForce(const ElementType & type, GhostType gt); /// assemble the stiffness matrix void assembleStiffnessMatrix(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); /// TODO remove void computeRotationMatrix(const ElementType & type); protected: /// compute Rotation Matrices template <const ElementType type> void computeRotationMatrix(__attribute__((unused)) Array<Real> & rotations) {} /* ------------------------------------------------------------------------ */ /* Mass (structural_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); /// computes rho void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type); /// finish the computation of residual to solve in increment void updateResidualInternal(); /* ------------------------------------------------------------------------ */ private: template <ElementType type> void assembleStiffnessMatrix(); template <ElementType type> void assembleMass(); template <ElementType type> void computeStressOnQuad(); template <ElementType type> void computeTangentModuli(Array<Real> & tangent_moduli); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: virtual dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind, const std::string & fe_engine_id = ""); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// set the value of the time step // void setTimeStep(Real time_step, const ID & solver_id = "") override; /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the StructuralMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement_rotation, Array<Real> &); /// get the StructuralMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array<Real> &); /// get the StructuralMechanicsModel::acceleration vector, updated /// by /// StructuralMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array<Real> &); /// get the StructuralMechanicsModel::external_force vector AKANTU_GET_MACRO(ExternalForce, *external_force, Array<Real> &); /// get the StructuralMechanicsModel::internal_force vector (boundary forces) AKANTU_GET_MACRO(InternalForce, *internal_force, Array<Real> &); /// get the StructuralMechanicsModel::boundary vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(RotationMatrix, rotation_matrix, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementMaterial, element_material, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Set_ID, set_ID, UInt); void addMaterial(StructuralMaterial & material) { materials.push_back(material); } const StructuralMaterial & getMaterial(const Element & element) const { return materials[element_material(element)]; } /* ------------------------------------------------------------------------ */ /* Boundaries (structural_mechanics_model_boundary.cc) */ /* ------------------------------------------------------------------------ */ public: /// Compute Linear load function set in global axis template <ElementType type> void computeForcesByGlobalTractionArray(const Array<Real> & tractions); /// Compute Linear load function set in local axis template <ElementType type> void computeForcesByLocalTractionArray(const Array<Real> & tractions); /// compute force vector from a function(x,y,momentum) that describe stresses // template <ElementType type> // void computeForcesFromFunction(BoundaryFunction in_function, // BoundaryFunctionType function_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array<Real> * displacement_rotation{nullptr}; /// velocities array Array<Real> * velocity{nullptr}; /// accelerations array Array<Real> * acceleration{nullptr}; /// forces array Array<Real> * internal_force{nullptr}; /// forces array Array<Real> * external_force{nullptr}; /// lumped mass array Array<Real> * mass{nullptr}; /// boundaries array Array<bool> * blocked_dofs{nullptr}; /// stress array ElementTypeMapArray<Real> stress; ElementTypeMapArray<UInt> element_material; // Define sets of beams ElementTypeMapArray<UInt> set_ID; /// number of degre of freedom UInt nb_degree_of_freedom; // Rotation matrix ElementTypeMapArray<Real> rotation_matrix; // /// analysis method check the list in akantu::AnalysisMethod // AnalysisMethod method; /// flag defining if the increment must be computed or not bool increment_flag; /* ------------------------------------------------------------------------ */ std::vector<StructuralMaterial> materials; }; } // namespace akantu #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model_boundary.cc b/src/model/structural_mechanics/structural_mechanics_model_boundary.cc index 10f0b31f2..8ed826ad6 100644 --- a/src/model/structural_mechanics/structural_mechanics_model_boundary.cc +++ b/src/model/structural_mechanics/structural_mechanics_model_boundary.cc @@ -1,47 +1,46 @@ /** * @file structural_mechanics_model_boundary.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Fri Oct 13 2017 * * @brief Implementation of the boundary conditions for * StructuralMechanicsModel * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integrator_gauss.hh" #include "model.hh" #include "shape_structural.hh" #include "structural_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc index 0a4bd6679..ebf76f302 100644 --- a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc +++ b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc @@ -1,370 +1,371 @@ /** * @file structural_mechanics_model_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of inline functions of StructuralMechanicsModel * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt StructuralMechanicsModel::getNbDegreeOfFreedom(const ElementType & type) const { UInt ndof = 0; #define GET_(type) ndof = ElementClass<type>::getNbDegreeOfFreedom() AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_, _ek_structural); #undef GET_ return ndof; } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeTangentModuli( Array<Real> & /*tangent_moduli*/) { AKANTU_TO_IMPLEMENT(); } } // namespace akantu #include "structural_element_bernoulli_beam_2.hh" #include "structural_element_bernoulli_beam_3.hh" #include "structural_element_kirchhoff_shell.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); auto nb_element = getFEEngine().getMesh().getNbElement(type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); auto tangent_size = ElementClass<type>::getNbStressComponents(); auto tangent_moduli = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); computeTangentModuli<type>(*tangent_moduli); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = nb_degree_of_freedom * nb_nodes_per_element; auto bt_d_b = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); const auto & b = getFEEngine().getShapesDerivatives(type); Matrix<Real> BtD(bt_d_b_size, tangent_size); for (auto && tuple : zip(make_view(b, tangent_size, bt_d_b_size), make_view(*tangent_moduli, tangent_size, tangent_size), make_view(*bt_d_b, bt_d_b_size, bt_d_b_size))) { auto & B = std::get<0>(tuple); auto & D = std::get<1>(tuple); auto & BtDB = std::get<2>(tuple); BtD.mul<true, false>(B, D); BtDB.template mul<false, false>(BtD, B); } /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto int_bt_d_b = std::make_unique<Array<Real>>( nb_element, bt_d_b_size * bt_d_b_size, "int_B^t*D*B"); getFEEngine().integrate(*bt_d_b, *int_bt_d_b, bt_d_b_size * bt_d_b_size, type); getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *int_bt_d_b, type, _not_ghost, _symmetric); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeStressOnQuad() { AKANTU_DEBUG_IN(); Array<Real> & sigma = stress(type, _not_ghost); auto nb_element = mesh.getNbElement(type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); auto tangent_size = ElementClass<type>::getNbStressComponents(); auto tangent_moduli = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); computeTangentModuli<type>(*tangent_moduli); /// compute DB auto d_b_size = nb_degree_of_freedom * nb_nodes_per_element; auto d_b = std::make_unique<Array<Real>>(nb_element * nb_quadrature_points, d_b_size * tangent_size, "D*B"); const auto & b = getFEEngine().getShapesDerivatives(type); auto B = b.begin(tangent_size, d_b_size); auto D = tangent_moduli->begin(tangent_size, tangent_size); auto D_B = d_b->begin(tangent_size, d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++B, ++D, ++D_B) { D_B->template mul<false, false>(*D, *B); } } /// compute DBu D_B = d_b->begin(tangent_size, d_b_size); auto DBu = sigma.begin(tangent_size); Array<Real> u_el(0, d_b_size); FEEngine::extractNodalToElementField(mesh, *displacement_rotation, u_el, type); auto ug = u_el.begin(d_b_size); // No need to rotate because B is post-multiplied for (UInt e = 0; e < nb_element; ++e, ++ug) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_B, ++DBu) { DBu->template mul<false>(*D_B, *ug); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeForcesByLocalTractionArray( const Array<Real> & tractions) { AKANTU_DEBUG_IN(); #if 0 UInt nb_element = getFEEngine().getMesh().getNbElement(type); UInt nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(type); UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); // check dimension match AKANTU_DEBUG_ASSERT( Mesh::getSpatialDimension(type) == getFEEngine().getElementDimension(), "element type dimension does not match the dimension of boundaries : " << getFEEngine().getElementDimension() << " != " << Mesh::getSpatialDimension(type)); // check size of the vector AKANTU_DEBUG_ASSERT( tractions.size() == nb_quad * nb_element, "the size of the vector should be the total number of quadrature points"); // check number of components AKANTU_DEBUG_ASSERT(tractions.getNbComponent() == nb_degree_of_freedom, "the number of components should be the spatial " "dimension of the problem"); Array<Real> Nvoigt(nb_element * nb_quad, nb_degree_of_freedom * nb_degree_of_freedom * nb_nodes_per_element); transferNMatrixToSymVoigtNMatrix<type>(Nvoigt); Array<Real>::const_matrix_iterator N_it = Nvoigt.begin( nb_degree_of_freedom, nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); auto te_it = tractions.begin(nb_degree_of_freedom); Array<Real> funct(nb_element * nb_quad, nb_degree_of_freedom * nb_nodes_per_element, 0.); Array<Real>::iterator<Vector<Real>> Fe_it = funct.begin(nb_degree_of_freedom * nb_nodes_per_element); Vector<Real> fe(nb_degree_of_freedom * nb_nodes_per_element); for (UInt e = 0; e < nb_element; ++e, ++T_it) { const Matrix<Real> & T = *T_it; for (UInt q = 0; q < nb_quad; ++q, ++N_it, ++te_it, ++Fe_it) { const Matrix<Real> & N = *N_it; const Vector<Real> & te = *te_it; Vector<Real> & Fe = *Fe_it; // compute N^t tl fe.mul<true>(N, te); // turn N^t tl back in the global referential Fe.mul<true>(T, fe); } } // allocate the vector that will contain the integrated values std::stringstream name; name << id << type << ":integral_boundary"; Array<Real> int_funct(nb_element, nb_degree_of_freedom * nb_nodes_per_element, name.str()); // do the integration getFEEngine().integrate(funct, int_funct, nb_degree_of_freedom * nb_nodes_per_element, type); // assemble the result into force vector getFEEngine().assembleArray(int_funct, *force_momentum, dof_synchronizer->getLocalDOFEquationNumbers(), nb_degree_of_freedom, type); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeForcesByGlobalTractionArray( const Array<Real> & traction_global) { AKANTU_DEBUG_IN(); #if 0 UInt nb_element = mesh.getNbElement(type); UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); UInt nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(type); std::stringstream name; name << id << ":structuralmechanics:imposed_linear_load"; Array<Real> traction_local(nb_element * nb_quad, nb_degree_of_freedom, name.str()); Array<Real>::const_matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_iterator<Vector<Real>> Te_it = traction_global.begin(nb_degree_of_freedom); Array<Real>::iterator<Vector<Real>> te_it = traction_local.begin(nb_degree_of_freedom); Matrix<Real> R(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e = 0; e < nb_element; ++e, ++T_it) { const Matrix<Real> & T = *T_it; for (UInt i = 0; i < nb_degree_of_freedom; ++i) for (UInt j = 0; j < nb_degree_of_freedom; ++j) R(i, j) = T(i, j); for (UInt q = 0; q < nb_quad; ++q, ++Te_it, ++te_it) { const Vector<Real> & Te = *Te_it; Vector<Real> & te = *te_it; // turn the traction in the local referential te.mul<false>(R, Te); } } computeForcesByLocalTractionArray<type>(traction_local); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @param myf pointer to a function that fills a vector/tensor with respect to * passed coordinates */ #if 0 template <ElementType type> inline void StructuralMechanicsModel::computeForcesFromFunction( BoundaryFunction myf, BoundaryFunctionType function_type) { /** function type is ** _bft_forces : linear load is given ** _bft_stress : stress function is given -> Not already done for this kind *of model */ std::stringstream name; name << id << ":structuralmechanics:imposed_linear_load"; Array<Real> lin_load(0, nb_degree_of_freedom, name.str()); name.clear(); UInt offset = nb_degree_of_freedom; // prepare the loop over element types UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); UInt nb_element = getFEEngine().getMesh().getNbElement(type); name.clear(); name << id << ":structuralmechanics:quad_coords"; Array<Real> quad_coords(nb_element * nb_quad, spatial_dimension, "quad_coords"); getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>(getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension); getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>( getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension, _not_ghost, empty_filter, true, 0, 1, 1); if (spatial_dimension == 3) getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>( getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension, _not_ghost, empty_filter, true, 0, 2, 2); lin_load.resize(nb_element * nb_quad); Real * imposed_val = lin_load.storage(); /// sigma/load on each quadrature points Real * qcoord = quad_coords.storage(); for (UInt el = 0; el < nb_element; ++el) { for (UInt q = 0; q < nb_quad; ++q) { myf(qcoord, imposed_val, NULL, 0); imposed_val += offset; qcoord += spatial_dimension; } } switch (function_type) { case _bft_traction_local: computeForcesByLocalTractionArray<type>(lin_load); break; case _bft_traction: computeForcesByGlobalTractionArray<type>(lin_load); break; default: break; } } #endif } // namespace akantu #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model_mass.cc b/src/model/structural_mechanics/structural_mechanics_model_mass.cc index b24eeb0d2..d26224be8 100644 --- a/src/model/structural_mechanics/structural_mechanics_model_mass.cc +++ b/src/model/structural_mechanics/structural_mechanics_model_mass.cc @@ -1,76 +1,79 @@ /** * @file structural_mechanics_model_mass.cc * + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jul 07 2014 - * @date last modification: Thu Oct 15 2015 + * @date last modification: Fri Dec 15 2017 * * @brief function handling mass computation * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "integrator_gauss.hh" #include "material.hh" #include "shape_structural.hh" #include "structural_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class ComputeRhoFunctorStruct { public: explicit ComputeRhoFunctorStruct(const StructuralMechanicsModel & model) : model(model){}; void operator()(Matrix<Real> & rho, const Element & element) const { Real mat_rho = model.getMaterial(element).rho; rho.set(mat_rho); } private: const StructuralMechanicsModel & model; }; /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleMass() { AKANTU_DEBUG_IN(); assembleMass(_not_ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleMass(GhostType ghost_type) { AKANTU_DEBUG_IN(); MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); ComputeRhoFunctorStruct compute_rho(*this); for (auto type : mesh.elementTypes(spatial_dimension, ghost_type, _ek_structural)) { fem.assembleFieldMatrix(compute_rho, "M", "displacement", this->getDOFManager(), type, ghost_type); } AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/model/time_step_solver.hh b/src/model/time_step_solver.hh index dfef977ca..4437296ea 100644 --- a/src/model/time_step_solver.hh +++ b/src/model/time_step_solver.hh @@ -1,137 +1,138 @@ /** * @file time_step_solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Aug 24 12:42:04 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Feb 21 2018 * * @brief This corresponding to the time step evolution solver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_memory.hh" #include "integration_scheme.hh" #include "parameter_registry.hh" #include "solver_callback.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TIME_STEP_SOLVER_HH__ #define __AKANTU_TIME_STEP_SOLVER_HH__ namespace akantu { class DOFManager; class NonLinearSolver; } namespace akantu { class TimeStepSolver : public Memory, public ParameterRegistry, public SolverCallback { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: TimeStepSolver(DOFManager & dof_manager, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver, const ID & id, UInt memory_id); ~TimeStepSolver() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// solves on step virtual void solveStep(SolverCallback & solver_callback) = 0; /// register an integration scheme for a given dof virtual void setIntegrationScheme(const ID & dof_id, const IntegrationSchemeType & type, IntegrationScheme::SolutionType solution_type = IntegrationScheme::_not_defined) = 0; /// replies if a integration scheme has been set virtual bool hasIntegrationScheme(const ID & dof_id) const = 0; /* ------------------------------------------------------------------------ */ /* Solver Callback interface */ /* ------------------------------------------------------------------------ */ public: /// implementation of the SolverCallback::getMatrixType() MatrixType getMatrixType(const ID &) final { return _mt_not_defined; } /// implementation of the SolverCallback::predictor() void predictor() override; /// implementation of the SolverCallback::corrector() void corrector() override; /// implementation of the SolverCallback::assembleJacobian() void assembleMatrix(const ID & matrix_id) override; /// implementation of the SolverCallback::assembleJacobian() void assembleLumpedMatrix(const ID & matrix_id) final; /// implementation of the SolverCallback::assembleResidual() void assembleResidual() override; /// implementation of the SolverCallback::assembleResidual() void assembleResidual(const ID & residual_part) override; void beforeSolveStep() override; void afterSolveStep() override; bool canSplitResidual() { return solver_callback->canSplitResidual(); } /* ------------------------------------------------------------------------ */ /* Accessor */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(TimeStep, time_step, Real); AKANTU_SET_MACRO(TimeStep, time_step, Real); AKANTU_GET_MACRO(NonLinearSolver, non_linear_solver, const NonLinearSolver &); AKANTU_GET_MACRO_NOT_CONST(NonLinearSolver, non_linear_solver, NonLinearSolver &); protected: MatrixType getCommonMatrixType(); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Underlying dof manager containing the dof to treat DOFManager & _dof_manager; /// Type of solver TimeStepSolverType type; /// The time step for this solver Real time_step; /// Temporary storage for solver callback SolverCallback * solver_callback; /// NonLinearSolver used by this tome step solver NonLinearSolver & non_linear_solver; /// List of required matrices std::map<std::string, MatrixType> needed_matrices; }; } // akantu #endif /* __AKANTU_TIME_STEP_SOLVER_HH__ */ diff --git a/src/model/time_step_solvers/time_step_solver.cc b/src/model/time_step_solvers/time_step_solver.cc index d936db10b..04bb9f871 100644 --- a/src/model/time_step_solvers/time_step_solver.cc +++ b/src/model/time_step_solvers/time_step_solver.cc @@ -1,177 +1,177 @@ /** * @file time_step_solver.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Oct 12 16:56:43 2015 + * @date creation: Tue Aug 18 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Implementation of common part of TimeStepSolvers * * @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) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "time_step_solver.hh" #include "dof_manager.hh" #include "non_linear_solver.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ TimeStepSolver::TimeStepSolver(DOFManager & dof_manager, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver, const ID & id, UInt memory_id) : Memory(id, memory_id), SolverCallback(dof_manager), _dof_manager(dof_manager), type(type), time_step(0.), solver_callback(nullptr), non_linear_solver(non_linear_solver) { this->registerSubRegistry("non_linear_solver", non_linear_solver); } /* -------------------------------------------------------------------------- */ TimeStepSolver::~TimeStepSolver() = default; /* -------------------------------------------------------------------------- */ MatrixType TimeStepSolver::getCommonMatrixType() { MatrixType common_type = _mt_not_defined; for (auto & pair : needed_matrices) { auto & type = pair.second; if (type == _mt_not_defined) { type = this->solver_callback->getMatrixType(pair.first); } common_type = std::min(common_type, type); } AKANTU_DEBUG_ASSERT(common_type != _mt_not_defined, "No type defined for the matrices"); return common_type; } /* -------------------------------------------------------------------------- */ void TimeStepSolver::predictor() { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); this->solver_callback->predictor(); } /* -------------------------------------------------------------------------- */ void TimeStepSolver::corrector() { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); this->solver_callback->corrector(); } /* -------------------------------------------------------------------------- */ void TimeStepSolver::beforeSolveStep() { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); this->solver_callback->beforeSolveStep(); } /* -------------------------------------------------------------------------- */ void TimeStepSolver::afterSolveStep() { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); this->solver_callback->afterSolveStep(); } /* -------------------------------------------------------------------------- */ void TimeStepSolver::assembleLumpedMatrix(const ID & matrix_id) { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); if (not _dof_manager.hasLumpedMatrix(matrix_id)) _dof_manager.getNewLumpedMatrix(matrix_id); this->solver_callback->assembleLumpedMatrix(matrix_id); } /* -------------------------------------------------------------------------- */ void TimeStepSolver::assembleMatrix(const ID & matrix_id) { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); auto common_type = this->getCommonMatrixType(); if (matrix_id != "J") { auto type = needed_matrices[matrix_id]; if (type == _mt_not_defined) return; if (not _dof_manager.hasMatrix(matrix_id)) { _dof_manager.getNewMatrix(matrix_id, type); } this->solver_callback->assembleMatrix(matrix_id); return; } if (not _dof_manager.hasMatrix("J")) _dof_manager.getNewMatrix("J", common_type); for (auto & pair : needed_matrices) { auto type = pair.second; if (type == _mt_not_defined) continue; auto name = pair.first; if (not _dof_manager.hasMatrix(name)) _dof_manager.getNewMatrix(name, type); this->solver_callback->assembleMatrix(name); } } /* -------------------------------------------------------------------------- */ void TimeStepSolver::assembleResidual() { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); this->_dof_manager.clearResidual(); this->solver_callback->assembleResidual(); } /* -------------------------------------------------------------------------- */ void TimeStepSolver::assembleResidual(const ID & residual_part) { AKANTU_DEBUG_ASSERT( this->solver_callback != nullptr, "This function cannot be called if the solver_callback is not set"); this->solver_callback->assembleResidual(residual_part); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/time_step_solvers/time_step_solver_default.cc b/src/model/time_step_solvers/time_step_solver_default.cc index 371050e61..cec055b5a 100644 --- a/src/model/time_step_solvers/time_step_solver_default.cc +++ b/src/model/time_step_solvers/time_step_solver_default.cc @@ -1,309 +1,310 @@ /** * @file time_step_solver_default.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Sep 16 10:20:55 2015 + * @date creation: Tue Sep 15 2015 + * @date last modification: Wed Feb 21 2018 * * @brief Default implementation of the time step solver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "time_step_solver_default.hh" #include "dof_manager_default.hh" #include "integration_scheme_1st_order.hh" #include "integration_scheme_2nd_order.hh" #include "mesh.hh" #include "non_linear_solver.hh" #include "pseudo_time.hh" #include "sparse_matrix_aij.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ TimeStepSolverDefault::TimeStepSolverDefault( DOFManagerDefault & dof_manager, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver, const ID & id, UInt memory_id) : TimeStepSolver(dof_manager, type, non_linear_solver, id, memory_id), dof_manager(dof_manager), is_mass_lumped(false) { switch (type) { case _tsst_dynamic: break; case _tsst_dynamic_lumped: this->is_mass_lumped = true; break; case _tsst_static: /// initialize a static time solver for callback dofs break; default: AKANTU_TO_IMPLEMENT(); } } /* -------------------------------------------------------------------------- */ void TimeStepSolverDefault::setIntegrationScheme( const ID & dof_id, const IntegrationSchemeType & type, IntegrationScheme::SolutionType solution_type) { if (this->integration_schemes.find(dof_id) != this->integration_schemes.end()) { AKANTU_EXCEPTION("Their DOFs " << dof_id << " have already an integration scheme associated"); } std::unique_ptr<IntegrationScheme> integration_scheme; if (this->is_mass_lumped) { switch (type) { case _ist_forward_euler: { integration_scheme = std::make_unique<ForwardEuler>(dof_manager, dof_id); break; } case _ist_central_difference: { integration_scheme = std::make_unique<CentralDifference>(dof_manager, dof_id); break; } default: AKANTU_EXCEPTION( "This integration scheme cannot be used in lumped dynamic"); } } else { switch (type) { case _ist_pseudo_time: { integration_scheme = std::make_unique<PseudoTime>(dof_manager, dof_id); break; } case _ist_forward_euler: { integration_scheme = std::make_unique<ForwardEuler>(dof_manager, dof_id); break; } case _ist_trapezoidal_rule_1: { integration_scheme = std::make_unique<TrapezoidalRule1>(dof_manager, dof_id); break; } case _ist_backward_euler: { integration_scheme = std::make_unique<BackwardEuler>(dof_manager, dof_id); break; } case _ist_central_difference: { integration_scheme = std::make_unique<CentralDifference>(dof_manager, dof_id); break; } case _ist_fox_goodwin: { integration_scheme = std::make_unique<FoxGoodwin>(dof_manager, dof_id); break; } case _ist_trapezoidal_rule_2: { integration_scheme = std::make_unique<TrapezoidalRule2>(dof_manager, dof_id); break; } case _ist_linear_acceleration: { integration_scheme = std::make_unique<LinearAceleration>(dof_manager, dof_id); break; } case _ist_generalized_trapezoidal: { integration_scheme = std::make_unique<GeneralizedTrapezoidal>(dof_manager, dof_id); break; } case _ist_newmark_beta: integration_scheme = std::make_unique<NewmarkBeta>(dof_manager, dof_id); break; } } AKANTU_DEBUG_ASSERT(integration_scheme, "No integration scheme was found for the provided types"); auto && matrices_names = integration_scheme->getNeededMatrixList(); for (auto && name : matrices_names) { needed_matrices.insert({name, _mt_not_defined}); } this->integration_schemes[dof_id] = std::move(integration_scheme); this->solution_types[dof_id] = solution_type; this->integration_schemes_owner.insert(dof_id); } /* -------------------------------------------------------------------------- */ bool TimeStepSolverDefault::hasIntegrationScheme(const ID & dof_id) const { return this->integration_schemes.find(dof_id) != this->integration_schemes.end(); } /* -------------------------------------------------------------------------- */ TimeStepSolverDefault::~TimeStepSolverDefault() = default; /* -------------------------------------------------------------------------- */ void TimeStepSolverDefault::solveStep(SolverCallback & solver_callback) { this->solver_callback = &solver_callback; this->solver_callback->beforeSolveStep(); this->non_linear_solver.solve(*this); this->solver_callback->afterSolveStep(); this->solver_callback = nullptr; } /* -------------------------------------------------------------------------- */ void TimeStepSolverDefault::predictor() { AKANTU_DEBUG_IN(); TimeStepSolver::predictor(); for (auto & pair : this->integration_schemes) { auto & dof_id = pair.first; auto & integration_scheme = pair.second; if (this->dof_manager.hasPreviousDOFs(dof_id)) { this->dof_manager.savePreviousDOFs(dof_id); } /// integrator predictor integration_scheme->predictor(this->time_step); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void TimeStepSolverDefault::corrector() { AKANTU_DEBUG_IN(); TimeStepSolver::corrector(); for (auto & pair : this->integration_schemes) { auto & dof_id = pair.first; auto & integration_scheme = pair.second; const auto & solution_type = this->solution_types[dof_id]; integration_scheme->corrector(solution_type, this->time_step); /// computing the increment of dof if needed if (this->dof_manager.hasDOFsIncrement(dof_id)) { if (!this->dof_manager.hasPreviousDOFs(dof_id)) { AKANTU_DEBUG_WARNING("In order to compute the increment of " << dof_id << " a 'previous' has to be registered"); continue; } Array<Real> & increment = this->dof_manager.getDOFsIncrement(dof_id); Array<Real> & previous = this->dof_manager.getPreviousDOFs(dof_id); UInt dof_array_comp = this->dof_manager.getDOFs(dof_id).getNbComponent(); auto prev_dof_it = previous.begin(dof_array_comp); auto incr_it = increment.begin(dof_array_comp); auto incr_end = increment.end(dof_array_comp); increment.copy(this->dof_manager.getDOFs(dof_id)); for (; incr_it != incr_end; ++incr_it, ++prev_dof_it) { *incr_it -= *prev_dof_it; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void TimeStepSolverDefault::assembleMatrix(const ID & matrix_id) { AKANTU_DEBUG_IN(); TimeStepSolver::assembleMatrix(matrix_id); if (matrix_id != "J") return; for (auto & pair : this->integration_schemes) { auto & dof_id = pair.first; auto & integration_scheme = pair.second; const auto & solution_type = this->solution_types[dof_id]; integration_scheme->assembleJacobian(solution_type, this->time_step); } this->dof_manager.applyBoundary("J"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void TimeStepSolverDefault::assembleResidual() { AKANTU_DEBUG_IN(); if (this->needed_matrices.find("M") != needed_matrices.end()) { if (this->is_mass_lumped) { this->assembleLumpedMatrix("M"); } else { this->assembleMatrix("M"); } } TimeStepSolver::assembleResidual(); for (auto & pair : this->integration_schemes) { auto & integration_scheme = pair.second; integration_scheme->assembleResidual(this->is_mass_lumped); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void TimeStepSolverDefault::assembleResidual(const ID & residual_part) { AKANTU_DEBUG_IN(); if (this->needed_matrices.find("M") != needed_matrices.end()) { if (this->is_mass_lumped) { this->assembleLumpedMatrix("M"); } else { this->assembleMatrix("M"); } } if (residual_part != "inertial") { TimeStepSolver::assembleResidual(residual_part); } if (residual_part == "inertial") { for (auto & pair : this->integration_schemes) { auto & integration_scheme = pair.second; integration_scheme->assembleResidual(this->is_mass_lumped); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/time_step_solvers/time_step_solver_default.hh b/src/model/time_step_solvers/time_step_solver_default.hh index 9996f657f..8dd17fbea 100644 --- a/src/model/time_step_solvers/time_step_solver_default.hh +++ b/src/model/time_step_solvers/time_step_solver_default.hh @@ -1,112 +1,113 @@ /** * @file time_step_solver_default.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Aug 24 17:10:29 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Feb 21 2018 * * @brief Default implementation for the time stepper * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integration_scheme.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #include <map> #include <set> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TIME_STEP_SOLVER_DEFAULT_HH__ #define __AKANTU_TIME_STEP_SOLVER_DEFAULT_HH__ namespace akantu { class DOFManagerDefault; } namespace akantu { class TimeStepSolverDefault : public TimeStepSolver { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: TimeStepSolverDefault(DOFManagerDefault & dof_manager, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver, const ID & id, UInt memory_id); ~TimeStepSolverDefault() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// registers an integration scheme for a given dof void setIntegrationScheme(const ID & dof_id, const IntegrationSchemeType & type, IntegrationScheme::SolutionType solution_type = IntegrationScheme::_not_defined) override; bool hasIntegrationScheme(const ID & dof_id) const override; /// implementation of the TimeStepSolver::predictor() void predictor() override; /// implementation of the TimeStepSolver::corrector() void corrector() override; /// implementation of the TimeStepSolver::assembleMatrix() void assembleMatrix(const ID & matrix_id) override; /// implementation of the TimeStepSolver::assembleResidual() void assembleResidual() override; void assembleResidual(const ID & residual_part) override; /// implementation of the generic TimeStepSolver::solveStep() void solveStep(SolverCallback & solver_callback) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: using DOFsIntegrationSchemes = std::map<ID, std::unique_ptr<IntegrationScheme>>; using DOFsIntegrationSchemesSolutionTypes = std::map<ID, IntegrationScheme::SolutionType>; using DOFsIntegrationSchemesOwner = std::set<ID>; /// DOFManager with its real type DOFManagerDefault & dof_manager; /// Underlying integration scheme per dof, \todo check what happens in dynamic /// in case of coupled equations DOFsIntegrationSchemes integration_schemes; /// defines if the solver is owner of the memory or not DOFsIntegrationSchemesOwner integration_schemes_owner; /// Type of corrector to use DOFsIntegrationSchemesSolutionTypes solution_types; /// define if the mass matrix is lumped or not bool is_mass_lumped; }; } // namespace akantu #endif /* __AKANTU_TIME_STEP_SOLVER_DEFAULT_HH__ */ diff --git a/src/model/time_step_solvers/time_step_solver_default_explicit.hh b/src/model/time_step_solvers/time_step_solver_default_explicit.hh index d23c30d3b..633730538 100644 --- a/src/model/time_step_solvers/time_step_solver_default_explicit.hh +++ b/src/model/time_step_solvers/time_step_solver_default_explicit.hh @@ -1,77 +1,78 @@ /** * @file time_step_solver_default_explicit.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Aug 24 14:21:44 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Default solver for explicit resolution * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TIME_STEP_SOLVER_DEFAULT_EXPLICIT_HH__ #define __AKANTU_TIME_STEP_SOLVER_DEFAULT_EXPLICIT_HH__ namespace akantu { class TimeStepSolverDefaultExplicit : public TimeStepSolverDefault { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: TimeStepSolverDefaultExplicit(); virtual ~TimeStepSolverDefaultExplicit(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void solveStep(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "time_step_solver_default_explicit_inline_impl.cc" /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const TimeStepSolverDefaultExplicit & _this) { _this.printself(stream); return stream; } } // akantu #endif /* __AKANTU_TIME_STEP_SOLVER_DEFAULT_EXPLICIT_HH__ */ diff --git a/src/model/time_step_solvers/time_step_solver_default_solver_callback.hh b/src/model/time_step_solvers/time_step_solver_default_solver_callback.hh index 9e0552b82..5d4c1d73d 100644 --- a/src/model/time_step_solvers/time_step_solver_default_solver_callback.hh +++ b/src/model/time_step_solvers/time_step_solver_default_solver_callback.hh @@ -1,63 +1,64 @@ /** * @file time_step_solver_default_solver_callback.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Sep 28 18:58:07 2015 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Jan 31 2018 * * @brief Implementation of the NonLinearSolverCallback for the time step * solver * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_linear_solver_callback.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TIME_STEP_SOLVER_DEFAULT_SOLVER_CALLBACK_HH__ #define __AKANTU_TIME_STEP_SOLVER_DEFAULT_SOLVER_CALLBACK_HH__ namespace akantu { class TimeStepSolverCallback : public NonLinearSolverCallback { /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// callback to assemble the Jacobian Matrix virtual void assembleJacobian(); /// callback to assemble the residual (rhs) virtual void assembleResidual(); /* ------------------------------------------------------------------------ */ /* Dynamic simulations part */ /* ------------------------------------------------------------------------ */ /// callback for the predictor (in case of dynamic simulation) virtual void predictor(); /// callback for the corrector (in case of dynamic simulation) virtual void corrector(); }; } // akantu #endif /* __AKANTU_TIME_STEP_SOLVER_DEFAULT_SOLVER_CALLBACK_HH__ */ diff --git a/src/python/python_functor.cc b/src/python/python_functor.cc index 15986dcf1..d4c524ca0 100644 --- a/src/python/python_functor.cc +++ b/src/python/python_functor.cc @@ -1,80 +1,80 @@ /** * @file python_functor.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Fri Nov 13 2015 + * @date last modification: Tue Feb 06 2018 * * @brief Python functor interface * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "python_functor.hh" #include "aka_common.hh" #include "internal_field.hh" #include <vector> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ PythonFunctor::PythonFunctor(PyObject * obj) : python_obj(obj) {} /* -------------------------------------------------------------------------- */ PyObject * PythonFunctor::callFunctor(PyObject * functor, PyObject * args, PyObject * kwargs) const { if (!PyCallable_Check(functor)) AKANTU_EXCEPTION("Provided functor is not a function"); PyObject * pValue = PyObject_Call(functor, args, kwargs); PyObject * exception_type = PyErr_Occurred(); if (exception_type) { PyObject * exception; PyObject * traceback; PyErr_Fetch(&exception_type, &exception, &traceback); PyObject_Print(exception_type, stdout, Py_PRINT_RAW); PyObject_Print(exception, stdout, Py_PRINT_RAW); std::stringstream sstr; sstr << "Exception occured while calling the functor: "; PyObject * exception_mesg = PyObject_GetAttrString(exception, "message"); #if PY_MAJOR_VERSION >= 3 if (exception_mesg && PyUnicode_Check(exception_mesg)) #else if (exception_mesg && PyString_Check(exception_mesg)) #endif sstr << this->convertToAkantu<std::string>(exception_mesg); else sstr << this->convertToAkantu<std::string>(exception); AKANTU_EXCEPTION(sstr.str()); } return pValue; } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/python/python_functor.hh b/src/python/python_functor.hh index effa1fc8f..ffda267b9 100644 --- a/src/python/python_functor.hh +++ b/src/python/python_functor.hh @@ -1,146 +1,146 @@ /** * @file python_functor.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Nov 15 2015 + * @date last modification: Wed Feb 07 2018 * * @brief Python Functor interface * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_group.hh" #include "internal_field.hh" /* -------------------------------------------------------------------------- */ #include <Python.h> #include <map> #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PYTHON_FUNCTOR_HH__ #define __AKANTU_PYTHON_FUNCTOR_HH__ namespace akantu { class PythonFunctor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PythonFunctor(PyObject * obj); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ /// call the python functor PyObject * callFunctor(PyObject * functor, PyObject * args, PyObject * kwargs) const; /// call the python functor from variadic types template <typename return_type, typename... Params> return_type callFunctor(const std::string & functor_name, Params &... parameters) const; /// empty function to cose the recursive template loop static inline void packArguments(std::vector<PyObject *> & pArgs); /// get the python function object inline PyObject * getPythonFunction(const std::string & functor_name) const; /// variadic template for unknown number of arguments to unpack template <typename T, typename... Args> static inline void packArguments(std::vector<PyObject *> & pArgs, T & p, Args &... params); /// convert an akantu object to python template <typename T> static inline PyObject * convertToPython(const T & akantu_obj); /// convert a stl vector to python template <typename T> static inline PyObject * convertToPython(const std::vector<T> & akantu_obj); /// convert a stl vector to python template <typename T> static inline PyObject * convertToPython(const std::vector<Array<T> *> & akantu_obj); /// convert a stl vector to python template <typename T> static inline PyObject * convertToPython(const std::unique_ptr<T> & akantu_obj); /// convert a stl vector to python template <typename T1, typename T2> static inline PyObject * convertToPython(const std::map<T1, T2> & akantu_obj); /// convert an akantu vector to python template <typename T> static inline PyObject * convertToPython(const Vector<T> & akantu_obj); /// convert an akantu internal to python template <typename T> static inline PyObject * convertToPython(const InternalField<T> & akantu_obj); /// convert an akantu vector to python template <typename T> static inline PyObject * convertToPython(const ElementTypeMapArray<T> & akantu_obj); /// convert an akantu vector to python template <typename T> static inline PyObject * convertToPython(const Array<T> & akantu_obj); /// convert an akantu vector to python template <typename T> static inline PyObject * convertToPython(Array<T> * akantu_obj); /// convert a akantu matrix to python template <typename T> static inline PyObject * convertToPython(const Matrix<T> & akantu_obj); /// convert a python object to an akantu object template <typename return_type> static inline return_type convertToAkantu(PyObject * python_obj); /// convert a python object to an akantu object template <typename T> static inline std::vector<T> convertListToAkantu(PyObject * python_obj); /// returns the numpy data type code template <typename T> static inline int getPythonDataTypeCode(); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: PyObject * python_obj; }; } // akantu #endif /* __AKANTU_PYTHON_FUNCTOR_HH__ */ #include "python_functor_inline_impl.cc" diff --git a/src/python/python_functor_inline_impl.cc b/src/python/python_functor_inline_impl.cc index e573bdabe..38ccd09da 100644 --- a/src/python/python_functor_inline_impl.cc +++ b/src/python/python_functor_inline_impl.cc @@ -1,462 +1,463 @@ /** * @file python_functor_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Fri Nov 13 2015 - * @date last modification: Wed Nov 18 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Python functor interface * * @section LICENSE * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "integration_point.hh" #include "internal_field.hh" /* -------------------------------------------------------------------------- */ #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <Python.h> #include <numpy/arrayobject.h> #include <typeinfo> #if PY_MAJOR_VERSION >= 3 #include <codecvt> #endif /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__ #define __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> inline int PythonFunctor::getPythonDataTypeCode() { AKANTU_EXCEPTION("undefined type: " << debug::demangle(typeid(T).name())); } /* -------------------------------------------------------------------------- */ template <> inline int PythonFunctor::getPythonDataTypeCode<bool>() { int data_typecode = NPY_NOTYPE; size_t s = sizeof(bool); switch (s) { case 1: data_typecode = NPY_BOOL; break; case 2: data_typecode = NPY_UINT16; break; case 4: data_typecode = NPY_UINT32; break; case 8: data_typecode = NPY_UINT64; break; } return data_typecode; } /* -------------------------------------------------------------------------- */ template <> inline int PythonFunctor::getPythonDataTypeCode<double>() { return NPY_DOUBLE; } /* -------------------------------------------------------------------------- */ template <> inline int PythonFunctor::getPythonDataTypeCode<UInt>() { return NPY_UINT; } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<double>(const double & akantu_object) { return PyFloat_FromDouble(akantu_object); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<UInt>(const UInt & akantu_object) { #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong(akantu_object); #else return PyInt_FromLong(akantu_object); #endif } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<int>(const int & akantu_object) { #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong(akantu_object); #else return PyInt_FromLong(akantu_object); #endif } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<bool>(const bool & akantu_object) { return PyBool_FromLong(long(akantu_object)); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<std::string>(const std::string & str) { #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromString(str.c_str()); #else return PyString_FromString(str.c_str()); #endif } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<NodeGroup>(const NodeGroup & group) { return PythonFunctor::convertToPython(group.getNodes()); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<ElementGroup>(const ElementGroup & group) { PyObject * res = PyDict_New(); PyDict_SetItem(res, PythonFunctor::convertToPython(std::string("element_group")), PythonFunctor::convertToPython(group.getElements())); PyDict_SetItem(res, PythonFunctor::convertToPython(std::string("node_group")), PythonFunctor::convertToPython(group.getNodeGroup())); return res; } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<ElementGroup *>(ElementGroup * const & group) { return PythonFunctor::convertToPython(*group); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<ElementType>(const ElementType & type) { // std::stringstream sstr; // sstr << type; // return PythonFunctor::convertToPython(sstr.str()); return PythonFunctor::convertToPython(int(type)); } /* -------------------------------------------------------------------------- */ template <typename T> inline PyObject * PythonFunctor::convertToPython(const ElementTypeMapArray<T> & map) { std::map<std::string, Array<T> *> res; for (const auto & type : map.elementTypes()) { std::stringstream sstr; sstr << type; res[sstr.str()] = const_cast<Array<T> *>(&map(type)); } return PythonFunctor::convertToPython(res); } /* -------------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const T &) { AKANTU_EXCEPTION(__PRETTY_FUNCTION__ << " : not implemented yet !" << std::endl << debug::demangle(typeid(T).name())); } /* -------------------------------------------------------------------------- */ template <typename T> inline PyObject * PythonFunctor::convertToPython(const std::vector<T> & array) { int data_typecode = getPythonDataTypeCode<T>(); npy_intp dims[1] = {int(array.size())}; PyObject * obj = PyArray_SimpleNewFromData(1, dims, data_typecode, const_cast<T *>(&array[0])); auto * res = (PyArrayObject *)obj; return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T> inline PyObject * PythonFunctor::convertToPython(const std::vector<Array<T> *> & array) { PyObject * res = PyDict_New(); for (auto a : array) { PyObject * obj = PythonFunctor::convertToPython(*a); PyObject * name = PythonFunctor::convertToPython(a->getID()); PyDict_SetItem(res, name, obj); } return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T1, typename T2> inline PyObject * PythonFunctor::convertToPython(const std::map<T1, T2> & map) { PyObject * res = PyDict_New(); for (auto && a : map) { PyObject * key = PythonFunctor::convertToPython(a.first); PyObject * value = PythonFunctor::convertToPython(a.second); PyDict_SetItem(res, key, value); } return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const Vector<T> & array) { int data_typecode = getPythonDataTypeCode<T>(); npy_intp dims[1] = {array.size()}; PyObject * obj = PyArray_SimpleNewFromData(1, dims, data_typecode, array.storage()); auto * res = (PyArrayObject *)obj; return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T> inline PyObject * PythonFunctor::convertToPython(const InternalField<T> & internals) { return convertToPython( static_cast<const ElementTypeMapArray<T> &>(internals)); } /* --------------------------------------------------------------------- */ template <typename T> inline PyObject * PythonFunctor::convertToPython(const std::unique_ptr<T> & u) { return convertToPython(*u); } /* --------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const Array<T> & array) { int data_typecode = getPythonDataTypeCode<T>(); npy_intp dims[2] = {array.size(), array.getNbComponent()}; PyObject * obj = PyArray_SimpleNewFromData(2, dims, data_typecode, array.storage()); auto * res = (PyArrayObject *)obj; return (PyObject *)res; } /* ---------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(Array<T> * array) { return PythonFunctor::convertToPython(*array); } /* ---------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const Matrix<T> & mat) { int data_typecode = getPythonDataTypeCode<T>(); npy_intp dims[2] = {mat.size(0), mat.size(1)}; PyObject * obj = PyArray_SimpleNewFromData(2, dims, data_typecode, mat.storage()); auto * res = (PyArrayObject *)obj; return (PyObject *)res; } /* ---------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<IntegrationPoint>(const IntegrationPoint & qp) { PyObject * input = PyDict_New(); PyObject * num_point = PythonFunctor::convertToPython(qp.num_point); PyObject * global_num = PythonFunctor::convertToPython(qp.global_num); PyObject * material_id = PythonFunctor::convertToPython(qp.material_id); PyObject * position = PythonFunctor::convertToPython(qp.getPosition()); PyDict_SetItemString(input, "num_point", num_point); PyDict_SetItemString(input, "global_num", global_num); PyDict_SetItemString(input, "material_id", material_id); PyDict_SetItemString(input, "position", position); return input; } /* -------------------------------------------------------------------------- */ inline PyObject * PythonFunctor::getPythonFunction(const std::string & functor_name) const { #if PY_MAJOR_VERSION < 3 if (!PyInstance_Check(this->python_obj)) AKANTU_EXCEPTION("Python object is not an instance"); #else // does not make sense to check everything is an instance of object in python 3 #endif if (not PyObject_HasAttrString(this->python_obj, functor_name.c_str())) AKANTU_EXCEPTION("Python dictionary has no " << functor_name << " entry"); PyObject * pFunctor = PyObject_GetAttrString(this->python_obj, functor_name.c_str()); return pFunctor; } /* -------------------------------------------------------------------------- */ inline void PythonFunctor::packArguments(__attribute__((unused)) std::vector<PyObject *> & p_args) {} /* -------------------------------------------------------------------------- */ template <typename T, typename... Args> inline void PythonFunctor::packArguments(std::vector<PyObject *> & p_args, T & p, Args &... params) { p_args.push_back(PythonFunctor::convertToPython(p)); if (sizeof...(params) != 0) PythonFunctor::packArguments(p_args, params...); } /* -------------------------------------------------------------------------- */ template <typename return_type, typename... Params> return_type PythonFunctor::callFunctor(const std::string & functor_name, Params &... parameters) const { _import_array(); std::vector<PyObject *> arg_vector; this->packArguments(arg_vector, parameters...); PyObject * pArgs = PyTuple_New(arg_vector.size()); for (UInt i = 0; i < arg_vector.size(); ++i) { PyTuple_SetItem(pArgs, i, arg_vector[i]); } PyObject * kwargs = PyDict_New(); PyObject * pFunctor = this->getPythonFunction(functor_name); PyObject * res = this->callFunctor(pFunctor, pArgs, kwargs); Py_XDECREF(pArgs); Py_XDECREF(kwargs); return this->convertToAkantu<return_type>(res); } /* -------------------------------------------------------------------------- */ template <typename return_type> inline return_type PythonFunctor::convertToAkantu(PyObject * python_obj) { if (PyList_Check(python_obj)) { return PythonFunctor::convertListToAkantu<typename return_type::value_type>( python_obj); } AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <> inline void PythonFunctor::convertToAkantu<void>(PyObject * python_obj) { if (python_obj != Py_None) AKANTU_DEBUG_WARNING( "functor return a value while none was expected: ignored"); } /* -------------------------------------------------------------------------- */ template <> inline std::string PythonFunctor::convertToAkantu<std::string>(PyObject * python_obj) { #if PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(python_obj)) AKANTU_EXCEPTION("cannot convert object to string"); std::wstring unicode_str(PyUnicode_AsWideCharString(python_obj, NULL)); std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; return converter.to_bytes(unicode_str); #else if (!PyString_Check(python_obj)) AKANTU_EXCEPTION("cannot convert object to string"); return PyString_AsString(python_obj); #endif } /* -------------------------------------------------------------------------- */ template <> inline Real PythonFunctor::convertToAkantu<Real>(PyObject * python_obj) { if (!PyFloat_Check(python_obj)) AKANTU_EXCEPTION("cannot convert object to float"); return PyFloat_AsDouble(python_obj); } /* -------------------------------------------------------------------------- */ template <> inline UInt PythonFunctor::convertToAkantu<UInt>(PyObject * python_obj) { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(python_obj)) AKANTU_EXCEPTION("cannot convert object to integer"); return PyLong_AsLong(python_obj); #else if (!PyInt_Check(python_obj)) AKANTU_EXCEPTION("cannot convert object to integer"); return PyInt_AsLong(python_obj); #endif } /* -------------------------------------------------------------------------- */ template <typename T> inline std::vector<T> PythonFunctor::convertListToAkantu(PyObject * python_obj) { std::vector<T> res; UInt size = PyList_Size(python_obj); for (UInt i = 0; i < size; ++i) { PyObject * item = PyList_GET_ITEM(python_obj, i); res.push_back(PythonFunctor::convertToAkantu<T>(item)); } return res; } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__ */ diff --git a/src/solver/petsc_wrapper.hh b/src/solver/petsc_wrapper.hh index dab92ca0d..e49a50350 100644 --- a/src/solver/petsc_wrapper.hh +++ b/src/solver/petsc_wrapper.hh @@ -1,79 +1,79 @@ /** * @file petsc_wrapper.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 21 2013 - * @date last modification: Wed Oct 07 2015 + * @date last modification: Sat Feb 03 2018 * * @brief Wrapper of PETSc structures * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PETSC_WRAPPER_HH__ #define __AKANTU_PETSC_WRAPPER_HH__ /* -------------------------------------------------------------------------- */ #include <mpi.h> #include <petscao.h> #include <petscis.h> #include <petscksp.h> #include <petscmat.h> #include <petscvec.h> namespace akantu { /* -------------------------------------------------------------------------- */ struct PETScMatrixWrapper { Mat mat; AO ao; ISLocalToGlobalMapping mapping; /// MPI communicator for PETSc commands MPI_Comm communicator; }; /* -------------------------------------------------------------------------- */ struct PETScSolverWrapper { KSP ksp; Vec solution; Vec rhs; // MPI communicator for PETSc commands MPI_Comm communicator; }; #if not defined(PETSC_CLANGUAGE_CXX) extern int aka_PETScError(int ierr); #define CHKERRXX(x) \ do { \ int error = aka_PETScError(x); \ if (error != 0) { \ AKANTU_EXCEPTION("Error in PETSC"); \ } \ } while (0) #endif } // akantu #endif /* __AKANTU_PETSC_WRAPPER_HH__ */ diff --git a/src/solver/solver_petsc.cc b/src/solver/solver_petsc.cc index b32a28b4c..7742143c7 100644 --- a/src/solver/solver_petsc.cc +++ b/src/solver/solver_petsc.cc @@ -1,1106 +1,1106 @@ /** * @file solver_petsc.cc * * @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue May 13 2014 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Sun Aug 13 2017 * * @brief Solver class implementation for the petsc solver * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solver_petsc.hh" #include "dof_manager_petsc.hh" #include "mpi_type_wrapper.hh" #include "sparse_matrix_petsc.hh" /* -------------------------------------------------------------------------- */ #include <petscksp.h> //#include <petscsys.h> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SolverPETSc::SolverPETSc(DOFManagerPETSc & dof_manager, const ID & matrix_id, const ID & id, const MemoryID & memory_id) : SparseSolver(dof_manager, matrix_id, id, memory_id), dof_manager(dof_manager), matrix(dof_manager.getMatrix(matrix_id)), is_petsc_data_initialized(false) { PetscErrorCode ierr; /// create a solver context ierr = KSPCreate(PETSC_COMM_WORLD, &this->ksp); CHKERRXX(ierr); } /* -------------------------------------------------------------------------- */ SolverPETSc::~SolverPETSc() { AKANTU_DEBUG_IN(); this->destroyInternalData(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::destroyInternalData() { AKANTU_DEBUG_IN(); if (this->is_petsc_data_initialized) { PetscErrorCode ierr; ierr = KSPDestroy(&(this->ksp)); CHKERRXX(ierr); this->is_petsc_data_initialized = false; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::initialize() { AKANTU_DEBUG_IN(); this->is_petsc_data_initialized = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::solve() { AKANTU_DEBUG_IN(); Vec & rhs = this->dof_manager.getResidual(); Vec & solution = this->dof_manager.getGlobalSolution(); PetscErrorCode ierr; ierr = KSPSolve(this->ksp, rhs, solution); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } // /* -------------------------------------------------------------------------- // */ // void SolverPETSc::solve(Array<Real> & solution) { // AKANTU_DEBUG_IN(); // this->solution = &solution; // this->solve(); // PetscErrorCode ierr; // PETScMatrix * petsc_matrix = static_cast<PETScMatrix *>(this->matrix); // // ierr = VecGetOwnershipRange(this->petsc_solver_wrapper->solution, // // solution_begin, solution_end); CHKERRXX(ierr); // // ierr = VecGetArray(this->petsc_solver_wrapper->solution, PetscScalar // // **array); CHKERRXX(ierr); // UInt nb_component = solution.getNbComponent(); // UInt size = solution.size(); // for (UInt i = 0; i < size; ++i) { // for (UInt j = 0; j < nb_component; ++j) { // UInt i_local = i * nb_component + j; // if (this->matrix->getDOFSynchronizer().isLocalOrMasterDOF(i_local)) { // Int i_global = // this->matrix->getDOFSynchronizer().getDOFGlobalID(i_local); // ierr = // AOApplicationToPetsc(petsc_matrix->getPETScMatrixWrapper()->ao, // 1, &(i_global)); // CHKERRXX(ierr); // ierr = VecGetValues(this->petsc_solver_wrapper->solution, 1, // &i_global, // &solution(i, j)); // CHKERRXX(ierr); // } // } // } // synch_registry->synchronize(_gst_solver_solution); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void SolverPETSc::setOperators() { AKANTU_DEBUG_IN(); PetscErrorCode ierr; /// set the matrix that defines the linear system and the matrix for /// preconditioning (here they are the same) #if PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 5 ierr = KSPSetOperators(this->ksp, this->matrix.getPETScMat(), this->matrix.getPETScMat()); CHKERRXX(ierr); #else ierr = KSPSetOperators(this->ksp, this->matrix.getPETScMat(), this->matrix.getPETScMat(), SAME_NONZERO_PATTERN); CHKERRXX(ierr); #endif /// If this is not called the solution vector is zeroed in the call to /// KSPSolve(). ierr = KSPSetInitialGuessNonzero(this->ksp, PETSC_TRUE); KSPSetFromOptions(this->ksp); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ // void finalize_petsc() { // static bool finalized = false; // if (!finalized) { // cout<<"*** INFO *** PETSc is finalizing..."<<endl; // // finalize PETSc // PetscErrorCode ierr = PetscFinalize();CHKERRCONTINUE(ierr); // finalized = true; // } // } // SolverPETSc::sparse_vector_type // SolverPETSc::operator()(const SolverPETSc::sparse_matrix_type& AA, // const SolverPETSc::sparse_vector_type& bb) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside PETSc solver: "<<timer<<endl; // #endif // #ifdef CPPUTILS_VERBOSE // out<<" Inside operator()(const sparse_matrix_type&, const // sparse_vector_type&)... "<<timer<<endl; // #endif // assert(AA.rows() == bb.size()); // // KSP ksp; //!< linear solver context // Vec b; /* RHS */ // PC pc; /* preconditioner context */ // PetscErrorCode ierr; // PetscInt nlocal; // PetscInt n = bb.size(); // VecScatter ctx; // /* // Create vectors. Note that we form 1 vector from scratch and // then duplicate as needed. For this simple case let PETSc decide how // many elements of the vector are stored on each processor. The second // argument to VecSetSizes() below causes PETSc to decide. // */ // ierr = VecCreate(PETSC_COMM_WORLD,&b);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(b,PETSC_DECIDE,n);CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(b);CHKERRCONTINUE(ierr); // if (!allocated_) { // ierr = VecDuplicate(b,&x_);CHKERRCONTINUE(ierr); // } else // VecZeroEntries(x_); // #ifdef CPPUTILS_VERBOSE // out<<" Vectors created... "<<timer<<endl; // #endif // /* Set hight-hand-side vector */ // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != // bb.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(b, 1, &row, &it->second, ADD_VALUES); // } // #ifdef CPPUTILS_VERBOSE // out<<" Right hand side set... "<<timer<<endl; // #endif // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(b);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(b);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Right-hand-side vector assembled... "<<timer<<endl; // ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // Vec b_all; // ierr = VecScatterCreateToAll(b, &ctx, &b_all);CHKERRCONTINUE(ierr); // ierr = // VecScatterBegin(ctx,b,b_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // ierr = // VecScatterEnd(ctx,b,b_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // value_type nrm; // VecNorm(b_all,NORM_2,&nrm); // out<<" Norm of right hand side... "<<nrm<<endl; // #endif // /* Identify the starting and ending mesh points on each // processor for the interior part of the mesh. We let PETSc decide // above. */ // // PetscInt rstart,rend; // // ierr = VecGetOwnershipRange(x_,&rstart,&rend);CHKERRCONTINUE(ierr); // ierr = VecGetLocalSize(x_,&nlocal);CHKERRCONTINUE(ierr); // /* // Create matrix. When using MatCreate(), the matrix format can // be specified at runtime. // Performance tuning note: For problems of substantial size, // preallocation of matrix memory is crucial for attaining good // performance. See the matrix chapter of the users manual for details. // We pass in nlocal as the "local" size of the matrix to force it // to have the same parallel layout as the vector created above. // */ // if (!allocated_) { // ierr = MatCreate(PETSC_COMM_WORLD,&A_);CHKERRCONTINUE(ierr); // ierr = MatSetSizes(A_,nlocal,nlocal,n,n);CHKERRCONTINUE(ierr); // ierr = MatSetFromOptions(A_);CHKERRCONTINUE(ierr); // ierr = MatSetUp(A_);CHKERRCONTINUE(ierr); // } else { // // zero-out matrix // MatZeroEntries(A_); // } // /* // Assemble matrix. // The linear system is distributed across the processors by // chunks of contiguous rows, which correspond to contiguous // sections of the mesh on which the problem is discretized. // For matrix assembly, each processor contributes entries for // the part that it owns locally. // */ // #ifdef CPPUTILS_VERBOSE // out<<" Zeroed-out sparse matrix entries... "<<timer<<endl; // #endif // for (sparse_matrix_type::const_hash_iterator it = AA.map_.begin(); it != // AA.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = AA.unhash(it->first); // PetscInt row = subs.first; // PetscInt col = subs.second; // ierr = MatSetValues(A_, 1, &row, 1, &col, &it->second, // ADD_VALUES);CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Filled sparse matrix... "<<timer<<endl; // #endif // /* Assemble the matrix */ // ierr = MatAssemblyBegin(A_,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(A_,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // if (!allocated_) { // // set after the first MatAssemblyEnd // // ierr = MatSetOption(A_, MAT_NEW_NONZERO_LOCATIONS, // PETSC_FALSE);CHKERRCONTINUE(ierr); // ierr = MatSetOption(A_, MAT_NEW_NONZERO_ALLOCATION_ERR, // PETSC_FALSE);CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Sparse matrix assembled... "<<timer<<endl; // // view matrix // MatView(A_, PETSC_VIEWER_STDOUT_WORLD); // MatNorm(A_,NORM_FROBENIUS,&nrm); // out<<" Norm of stiffness matrix... "<<nrm<<endl; // #endif // /* // Set operators. Here the matrix that defines the linear system // also serves as the preconditioning matrix. // */ // // ierr = // KSPSetOperators(ksp,A_,A_,DIFFERENT_NONZERO_PATTERN);CHKERRCONTINUE(ierr); // ierr = // KSPSetOperators(ksp_,A_,A_,SAME_NONZERO_PATTERN);CHKERRCONTINUE(ierr); // // // // /* // // Set runtime options, e.g., // // -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol> // // These options will override those specified above as long as // // KSPSetFromOptions() is called _after_ any other customization // // routines. // // */ // // ierr = KSPSetFromOptions(ksp);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Solving system... "<<timer<<endl; // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Solve the linear system // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // /* // Solve linear system // */ // ierr = KSPSolve(ksp_,b,x_);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // /* // View solver info; we could instead use the option -ksp_view to // print this info to the screen at the conclusion of KSPSolve(). // */ // ierr = KSPView(ksp_,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // int iter; // KSPGetIterationNumber(ksp_, &iter); // out<<" System solved in "<<iter<<" iterations... "<<timer<<endl; // KSPConvergedReason reason; // ierr = KSPGetConvergedReason(ksp_,&reason);CHKERRCONTINUE(ierr); // if (reason < 0) // out<<"*** WARNING *** PETSc solver diverged with flag "; // else // out<<"*** INFO *** PETSc solver converged with flag "; // if (reason == KSP_CONVERGED_RTOL) // out<<"KSP_CONVERGED_RTOL"<<endl; // else if (reason == KSP_CONVERGED_ATOL) // out<<"KSP_CONVERGED_ATOL"<<endl; // else if (reason == KSP_CONVERGED_ITS) // out<<"KSP_CONVERGED_ITS"<<endl; // else if (reason == KSP_CONVERGED_CG_NEG_CURVE) // out<<"KSP_CONVERGED_CG_NEG_CURVE"<<endl; // else if (reason == KSP_CONVERGED_CG_CONSTRAINED) // out<<"KSP_CONVERGED_CG_CONSTRAINED"<<endl; // else if (reason == KSP_CONVERGED_STEP_LENGTH) // out<<"KSP_CONVERGED_STEP_LENGTH"<<endl; // else if (reason == KSP_CONVERGED_HAPPY_BREAKDOWN) // out<<"KSP_CONVERGED_HAPPY_BREAKDOWN"<<endl; // else if (reason == KSP_DIVERGED_NULL) // out<<"KSP_DIVERGED_NULL"<<endl; // else if (reason == KSP_DIVERGED_ITS) // out<<"KSP_DIVERGED_ITS"<<endl; // else if (reason == KSP_DIVERGED_DTOL) // out<<"KSP_DIVERGED_DTOL"<<endl; // else if (reason == KSP_DIVERGED_BREAKDOWN) // out<<"KSP_DIVERGED_BREAKDOWN"<<endl; // else if (reason == KSP_DIVERGED_BREAKDOWN_BICG) // out<<"KSP_DIVERGED_BREAKDOWN_BICG"<<endl; // else if (reason == KSP_DIVERGED_NONSYMMETRIC) // out<<"KSP_DIVERGED_NONSYMMETRIC"<<endl; // else if (reason == KSP_DIVERGED_INDEFINITE_PC) // out<<"KSP_DIVERGED_INDEFINITE_PC"<<endl; // else if (reason == KSP_DIVERGED_NAN) // out<<"KSP_DIVERGED_NAN"<<endl; // else if (reason == KSP_DIVERGED_INDEFINITE_MAT) // out<<"KSP_DIVERGED_INDEFINITE_MAT"<<endl; // else if (reason == KSP_CONVERGED_ITERATING) // out<<"KSP_CONVERGED_ITERATING"<<endl; // PetscReal rnorm; // ierr = KSPGetResidualNorm(ksp_,&rnorm);CHKERRCONTINUE(ierr); // out<<"PETSc last residual norm computed: "<<rnorm<<endl; // ierr = VecView(x_,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // VecNorm(x_,NORM_2,&nrm); // out<<" Norm of solution vector... "<<nrm<<endl; // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check solution and clean up // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // Vec x_all; // ierr = VecScatterCreateToAll(x_, &ctx, &x_all);CHKERRCONTINUE(ierr); // ierr = // VecScatterBegin(ctx,x_,x_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // ierr = // VecScatterEnd(ctx,x_,x_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Solution vector scattered... "<<timer<<endl; // VecNorm(x_all,NORM_2,&nrm); // out<<" Norm of scattered vector... "<<nrm<<endl; // // ierr = VecView(x_all,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get values from solution and store them in the object that will be // returned // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // sparse_vector_type xx(bb.size()); // /* Set solution vector */ // double zero = 0.; // double val; // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != // bb.map_.end(); ++it) { // int row = it->first; // ierr = VecGetValues(x_all, 1, &row, &val); // if (val != zero) // xx[row] = val; // } // #ifdef CPPUTILS_VERBOSE // out<<" Solution vector copied... "<<timer<<endl; // // out<<" Norm of copied solution vector... "<<norm(xx, // Insert_t)<<endl; // #endif // /* // Free work space. All PETSc objects should be destroyed when they // are no longer needed. // */ // ierr = VecDestroy(&b);CHKERRCONTINUE(ierr); // // ierr = KSPDestroy(&ksp);CHKERRCONTINUE(ierr); // // set allocated flag // if (!allocated_) { // allocated_ = true; // } // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return xx; // } // SolverPETSc::sparse_vector_type SolverPETSc::operator()(const // SolverPETSc::sparse_matrix_type& KKpf, const SolverPETSc::sparse_matrix_type& // KKpp, const SolverPETSc::sparse_vector_type& UUp) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::operator()(const sparse_matrix&, const // sparse_matrix&, const sparse_vector&). "<<timer<<endl; // #endif // Mat Kpf, Kpp; // Vec Up, Pf, Pp; // PetscErrorCode ierr = // MatCreate(PETSC_COMM_WORLD,&Kpf);CHKERRCONTINUE(ierr); // ierr = MatCreate(PETSC_COMM_WORLD,&Kpp);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Allocating memory... "<<timer<<endl; // #endif // ierr = MatSetFromOptions(Kpf);CHKERRCONTINUE(ierr); // ierr = MatSetFromOptions(Kpp);CHKERRCONTINUE(ierr); // ierr = MatSetSizes(Kpf,PETSC_DECIDE,PETSC_DECIDE, KKpf.rows(), // KKpf.columns());CHKERRCONTINUE(ierr); // ierr = MatSetSizes(Kpp,PETSC_DECIDE,PETSC_DECIDE, KKpp.rows(), // KKpp.columns());CHKERRCONTINUE(ierr); // // get number of non-zeros in both diagonal and non-diagonal portions of // the matrix // std::pair<size_t,size_t> Kpf_nz = KKpf.non_zero_off_diagonal(); // std::pair<size_t,size_t> Kpp_nz = KKpp.non_zero_off_diagonal(); // ierr = MatMPIAIJSetPreallocation(Kpf, Kpf_nz.first, PETSC_NULL, // Kpf_nz.second, PETSC_NULL); CHKERRCONTINUE(ierr); // ierr = MatMPIAIJSetPreallocation(Kpp, Kpp_nz.first, PETSC_NULL, // Kpp_nz.second, PETSC_NULL); CHKERRCONTINUE(ierr); // ierr = MatSeqAIJSetPreallocation(Kpf, Kpf_nz.first, PETSC_NULL); // CHKERRCONTINUE(ierr); // ierr = MatSeqAIJSetPreallocation(Kpp, Kpp_nz.first, PETSC_NULL); // CHKERRCONTINUE(ierr); // for (sparse_matrix_type::const_hash_iterator it = KKpf.map_.begin(); it != // KKpf.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = KKpf.unhash(it->first); // int row = subs.first; // int col = subs.second; // ierr = MatSetValues(Kpf, 1, &row, 1, &col, &it->second, // ADD_VALUES);CHKERRCONTINUE(ierr); // } // for (sparse_matrix_type::const_hash_iterator it = KKpp.map_.begin(); it != // KKpp.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = KKpp.unhash(it->first); // int row = subs.first; // int col = subs.second; // ierr = MatSetValues(Kpf, 1, &row, 1, &col, &it->second, // ADD_VALUES);CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Filled sparse matrices... "<<timer<<endl; // #endif // /* // Assemble matrix, using the 2-step process: // MatAssemblyBegin(), MatAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = MatAssemblyBegin(Kpf,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyBegin(Kpp,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(Kpf,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(Kpp,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Sparse matrices assembled... "<<timer<<endl; // #endif // ierr = VecCreate(PETSC_COMM_WORLD,&Up);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(Up,PETSC_DECIDE, UUp.size());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(Up);CHKERRCONTINUE(ierr); // ierr = VecCreate(PETSC_COMM_WORLD,&Pf);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(Pf,PETSC_DECIDE, KKpf.rows());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(Pf);CHKERRCONTINUE(ierr); // ierr = VecDuplicate(Pf,&Pp);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vectors created... "<<timer<<endl; // #endif // /* Set hight-hand-side vector */ // for (sparse_vector_type::const_hash_iterator it = UUp.map_.begin(); it != // UUp.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(Up, 1, &row, &it->second, ADD_VALUES); // } // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(Up);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(Up);CHKERRCONTINUE(ierr); // // add Kpf*Uf // ierr = MatMult(Kpf, x_, Pf); // // add Kpp*Up // ierr = MatMultAdd(Kpp, Up, Pf, Pp); // #ifdef CPPUTILS_VERBOSE // out<<" Matrices multiplied... "<<timer<<endl; // #endif // VecScatter ctx; // Vec Pp_all; // ierr = VecScatterCreateToAll(Pp, &ctx, &Pp_all);CHKERRCONTINUE(ierr); // ierr = // VecScatterBegin(ctx,Pp,Pp_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // ierr = // VecScatterEnd(ctx,Pp,Pp_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vector scattered... "<<timer<<endl; // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get values from solution and store them in the object that will be // returned // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // sparse_vector_type pp(KKpf.rows()); // // get reaction vector // for (int i=0; i<KKpf.rows(); ++i) { // PetscScalar v; // ierr = VecGetValues(Pp_all, 1, &i, &v); // if (v != PetscScalar()) // pp[i] = v; // } // #ifdef CPPUTILS_VERBOSE // out<<" Vector copied... "<<timer<<endl; // #endif // ierr = MatDestroy(&Kpf);CHKERRCONTINUE(ierr); // ierr = MatDestroy(&Kpp);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Up);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Pf);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Pp);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Pp_all);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return pp; // } // SolverPETSc::sparse_vector_type SolverPETSc::operator()(const // SolverPETSc::sparse_vector_type& aa, const SolverPETSc::sparse_vector_type& // bb) { // assert(aa.size() == bb.size()); // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::operator()(const sparse_vector&, const // sparse_vector&). "<<timer<<endl; // #endif // Vec r; // PetscErrorCode ierr = VecCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(r,PETSC_DECIDE, aa.size());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vectors created... "<<timer<<endl; // #endif // // set values // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != // aa.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES); // } // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != // bb.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES); // } // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(r);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(r);CHKERRCONTINUE(ierr); // sparse_vector_type rr(aa.size()); // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != // aa.map_.end(); ++it) { // int row = it->first; // ierr = VecGetValues(r, 1, &row, &rr[row]); // } // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != // bb.map_.end(); ++it) { // int row = it->first; // ierr = VecGetValues(r, 1, &row, &rr[row]); // } // #ifdef CPPUTILS_VERBOSE // out<<" Vector copied... "<<timer<<endl; // #endif // ierr = VecDestroy(&r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return rr; // } // SolverPETSc::value_type SolverPETSc::norm(const // SolverPETSc::sparse_matrix_type& aa, Element_insertion_type flag) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::norm(const sparse_matrix&). "<<timer<<endl; // #endif // Mat r; // PetscErrorCode ierr = MatCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr); // ierr = MatSetSizes(r,PETSC_DECIDE,PETSC_DECIDE, aa.rows(), // aa.columns());CHKERRCONTINUE(ierr); // ierr = MatSetFromOptions(r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Matrix created... "<<timer<<endl; // #endif // // set values // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != // aa.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = aa.unhash(it->first); // int row = subs.first; // int col = subs.second; // if (flag == Add_t) // ierr = MatSetValues(r, 1, &row, 1, &col, &it->second, ADD_VALUES); // else if (flag == Insert_t) // ierr = MatSetValues(r, 1, &row, 1, &col, &it->second, INSERT_VALUES); // CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Matrix filled..."<<timer<<endl; // #endif // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = MatAssemblyBegin(r,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(r,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // value_type nrm; // MatNorm(r,NORM_FROBENIUS,&nrm); // #ifdef CPPUTILS_VERBOSE // out<<" Norm computed... "<<timer<<endl; // #endif // ierr = MatDestroy(&r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return nrm; // } // SolverPETSc::value_type SolverPETSc::norm(const // SolverPETSc::sparse_vector_type& aa, Element_insertion_type flag) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::norm(const sparse_vector&). "<<timer<<endl; // #endif // Vec r; // PetscErrorCode ierr = VecCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(r,PETSC_DECIDE, aa.size());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vector created... "<<timer<<endl; // #endif // // set values // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != // aa.map_.end(); ++it) { // int row = it->first; // if (flag == Add_t) // ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES); // else if (flag == Insert_t) // ierr = VecSetValues(r, 1, &row, &it->second, INSERT_VALUES); // CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Vector filled..."<<timer<<endl; // #endif // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(r);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(r);CHKERRCONTINUE(ierr); // value_type nrm; // VecNorm(r,NORM_2,&nrm); // #ifdef CPPUTILS_VERBOSE // out<<" Norm computed... "<<timer<<endl; // #endif // ierr = VecDestroy(&r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return nrm; // } // // // ///* // -------------------------------------------------------------------------- */ // //SolverMumps::SolverMumps(SparseMatrix & matrix, // // const ID & id, // // const MemoryID & memory_id) : // //Solver(matrix, id, memory_id), is_mumps_data_initialized(false), // rhs_is_local(true) { // // AKANTU_DEBUG_IN(); // // // //#ifdef AKANTU_USE_MPI // // parallel_method = SolverMumpsOptions::_fully_distributed; // //#else //AKANTU_USE_MPI // // parallel_method = SolverMumpsOptions::_master_slave_distributed; // //#endif //AKANTU_USE_MPI // // // // CommunicatorEventHandler & comm_event_handler = *this; // // // // communicator.registerEventHandler(comm_event_handler); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* // -------------------------------------------------------------------------- */ // //SolverMumps::~SolverMumps() { // // AKANTU_DEBUG_IN(); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* // -------------------------------------------------------------------------- */ // //void SolverMumps::destroyMumpsData() { // // AKANTU_DEBUG_IN(); // // // // if(is_mumps_data_initialized) { // // mumps_data.job = _smj_destroy; // destroy // // dmumps_c(&mumps_data); // // is_mumps_data_initialized = false; // // } // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* // -------------------------------------------------------------------------- */ // //void SolverMumps::onCommunicatorFinalize(const StaticCommunicator & comm) { // // AKANTU_DEBUG_IN(); // // // // try{ // // const StaticCommunicatorMPI & comm_mpi = // // dynamic_cast<const StaticCommunicatorMPI // &>(comm.getRealStaticCommunicator()); // // if(mumps_data.comm_fortran == // MPI_Comm_c2f(comm_mpi.getMPICommunicator())) // // destroyMumpsData(); // // } catch(...) {} // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* // -------------------------------------------------------------------------- */ // //void SolverMumps::initMumpsData(SolverMumpsOptions::ParallelMethod // parallel_method) { // // switch(parallel_method) { // // case SolverMumpsOptions::_fully_distributed: // // icntl(18) = 3; //fully distributed // // icntl(28) = 0; //automatic choice // // // // mumps_data.nz_loc = matrix->getNbNonZero(); // // mumps_data.irn_loc = matrix->getIRN().values; // // mumps_data.jcn_loc = matrix->getJCN().values; // // break; // // case SolverMumpsOptions::_master_slave_distributed: // // if(prank == 0) { // // mumps_data.nz = matrix->getNbNonZero(); // // mumps_data.irn = matrix->getIRN().values; // // mumps_data.jcn = matrix->getJCN().values; // // } else { // // mumps_data.nz = 0; // // mumps_data.irn = NULL; // // mumps_data.jcn = NULL; // // // // icntl(18) = 0; //centralized // // icntl(28) = 0; //sequential analysis // // } // // break; // // } // //} // // // ///* // -------------------------------------------------------------------------- */ // //void SolverMumps::initialize(SolverOptions & options) { // // AKANTU_DEBUG_IN(); // // // // mumps_data.par = 1; // // // // if(SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions // *>(&options)) { // // if(opt->parallel_method == // SolverMumpsOptions::_master_slave_distributed) { // // mumps_data.par = 0; // // } // // } // // // // mumps_data.sym = 2 * (matrix->getSparseMatrixType() == _symmetric); // // prank = communicator.whoAmI(); // //#ifdef AKANTU_USE_MPI // // mumps_data.comm_fortran = MPI_Comm_c2f(dynamic_cast<const // StaticCommunicatorMPI // &>(communicator.getRealStaticCommunicator()).getMPICommunicator()); // //#endif // // // // if(AKANTU_DEBUG_TEST(dblTrace)) { // // icntl(1) = 2; // // icntl(2) = 2; // // icntl(3) = 2; // // icntl(4) = 4; // // } // // // // mumps_data.job = _smj_initialize; //initialize // // dmumps_c(&mumps_data); // // is_mumps_data_initialized = true; // // // // /* // ------------------------------------------------------------------------ */ // // UInt size = matrix->size(); // // // // if(prank == 0) { // // std::stringstream sstr_rhs; sstr_rhs << id << ":rhs"; // // rhs = &(alloc<Real>(sstr_rhs.str(), size, 1, REAL_INIT_VALUE)); // // } else { // // rhs = NULL; // // } // // // // /// No outputs // // icntl(1) = 0; // // icntl(2) = 0; // // icntl(3) = 0; // // icntl(4) = 0; // // mumps_data.nz_alloc = 0; // // // // if (AKANTU_DEBUG_TEST(dblDump)) icntl(4) = 4; // // // // mumps_data.n = size; // // // // if(AKANTU_DEBUG_TEST(dblDump)) { // // strcpy(mumps_data.write_problem, "mumps_matrix.mtx"); // // } // // // // /* // ------------------------------------------------------------------------ */ // // // Default Scaling // // icntl(8) = 77; // // // // icntl(5) = 0; // Assembled matrix // // // // SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions *>(&options); // // if(opt) // // parallel_method = opt->parallel_method; // // // // initMumpsData(parallel_method); // // // // mumps_data.job = _smj_analyze; //analyze // // dmumps_c(&mumps_data); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* // -------------------------------------------------------------------------- */ // //void SolverMumps::setRHS(Array<Real> & rhs) { // // if(prank == 0) { // // matrix->getDOFSynchronizer().gather(rhs, 0, this->rhs); // // } else { // // matrix->getDOFSynchronizer().gather(rhs, 0); // // } // //} // // // ///* // -------------------------------------------------------------------------- */ // //void SolverMumps::solve() { // // AKANTU_DEBUG_IN(); // // // // if(parallel_method == SolverMumpsOptions::_fully_distributed) // // mumps_data.a_loc = matrix->getA().values; // // else // // if(prank == 0) { // // mumps_data.a = matrix->getA().values; // // } // // // // if(prank == 0) { // // mumps_data.rhs = rhs->values; // // } // // // // /// Default centralized dense second member // // icntl(20) = 0; // // icntl(21) = 0; // // // // mumps_data.job = _smj_factorize_solve; //solve // // dmumps_c(&mumps_data); // // // // AKANTU_DEBUG_ASSERT(info(1) != -10, "Singular matrix"); // // AKANTU_DEBUG_ASSERT(info(1) == 0, // // "Error in mumps during solve process, check mumps // user guide INFO(1) =" // // << info(1)); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* // -------------------------------------------------------------------------- */ // //void SolverMumps::solve(Array<Real> & solution) { // // AKANTU_DEBUG_IN(); // // // // solve(); // // // // if(prank == 0) { // // matrix->getDOFSynchronizer().scatter(solution, 0, this->rhs); // // } else { // // matrix->getDOFSynchronizer().scatter(solution, 0); // // } // // // // AKANTU_DEBUG_OUT(); // //} } // akantu diff --git a/src/solver/solver_petsc.hh b/src/solver/solver_petsc.hh index 241884da4..76837b321 100644 --- a/src/solver/solver_petsc.hh +++ b/src/solver/solver_petsc.hh @@ -1,183 +1,185 @@ /** * @file solver_petsc.hh * * @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue May 13 2014 - * @date last modification: Wed Oct 07 2015 + * @date last modification: Mon Jun 19 2017 * * @brief Solver class interface for the petsc solver * * @section LICENSE * - * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2014-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "sparse_solver.hh" /* -------------------------------------------------------------------------- */ #include <petscksp.h> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLVER_PETSC_HH__ #define __AKANTU_SOLVER_PETSC_HH__ namespace akantu { class SparseMatrixPETSc; class DOFManagerPETSc; } namespace akantu { class SolverPETSc : public SparseSolver { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SolverPETSc(DOFManagerPETSc & dof_manager, const ID & matrix_id, const ID & id = "solver_petsc", const MemoryID & memory_id = 0); virtual ~SolverPETSc(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// create the solver context and set the matrices virtual void initialize(); virtual void setOperators(); virtual void setRHS(Array<Real> & rhs); virtual void solve(); virtual void solve(Array<Real> & solution); private: /// clean the petsc data virtual void destroyInternalData(); private: /// DOFManager correctly typed DOFManagerPETSc & dof_manager; /// PETSc linear solver KSP ksp; /// Matrix defining the system of equations SparseMatrixPETSc & matrix; /// specify if the petsc_data is initialized or not bool is_petsc_data_initialized; }; // SolverPETSc(int argc, char *argv[]) : allocated_(false) { // /* // Set linear solver defaults for this problem (optional). // - By extracting the KSP and PC contexts from the KSP context, // we can then directly call any KSP and PC routines to set // various options. // - The following four statements are optional; all of these // parameters could alternatively be specified at runtime via // KSPSetFromOptions(); // */ // // ierr = KSPGetPC(ksp_,&pc);CHKERRCONTINUE(ierr); // // ierr = PCSetType(pc,PCILU);CHKERRCONTINUE(ierr); // // ierr = PCSetType(pc,PCJACOBI);CHKERRCONTINUE(ierr); // ierr = // KSPSetTolerances(ksp_,1.e-5,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRCONTINUE(ierr); // } // //! Overload operator() to solve system of linear equations // sparse_vector_type operator()(const sparse_matrix_type& AA, const // sparse_vector_type& bb); // //! Overload operator() to obtain reaction vector // sparse_vector_type operator()(const sparse_matrix_type& Kpf, const // sparse_matrix_type& Kpp, const sparse_vector_type& Up); // //! Overload operator() to obtain the addition two vectors // sparse_vector_type operator()(const sparse_vector_type& aa, const // sparse_vector_type& bb); // value_type norm(const sparse_matrix_type& aa, Element_insertion_type it = // Add_t); // value_type norm(const sparse_vector_type& aa, Element_insertion_type it = // Add_t); // // NOTE: the destructor will return an error if it is called after // MPI_Finalize is // // called because it uses collect communication to free-up allocated // memory. // ~SolverPETSc() { // static bool exit = false; // if (!exit) { // // add finalize PETSc function at exit // atexit(finalize); // exit = true; // } // if (allocated_) { // PetscErrorCode ierr = MatDestroy(&A_);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&x_);CHKERRCONTINUE(ierr); // ierr = KSPDestroy(&ksp_);CHKERRCONTINUE(ierr); // } // } // /* from the PETSc library, these are the options that can be passed // to the command line // Options Database Keys // -options_table - Calls PetscOptionsView() -// -options_left - Prints unused options that remain in the +// -options_left - Prints unused options that remain in +// the // database // -objects_left - Prints list of all objects that have not // been freed // -mpidump - Calls PetscMPIDump() // -malloc_dump - Calls PetscMallocDump() // -malloc_info - Prints total memory usage // -malloc_log - Prints summary of memory usage // Options Database Keys for Profiling // -log_summary [filename] - Prints summary of flop and timing // information to screen. // If the filename is specified the summary is written to the file. See // PetscLogView(). // -log_summary_python [filename] - Prints data on of flop and timing // usage // to a file or screen. -// -log_all [filename] - Logs extensive profiling information See +// -log_all [filename] - Logs extensive profiling information +// See // PetscLogDump(). // -log [filename] - Logs basic profiline information See // PetscLogDump(). // -log_sync - Log the synchronization in scatters, // inner products and norms // -log_mpe [filename] - Creates a logfile viewable by the utility // Upshot/Nupshot (in MPICH distribution) // } // } // }; } // akantu #endif /* __AKANTU_SOLVER_PETSC_HH__ */ diff --git a/src/solver/sparse_matrix.cc b/src/solver/sparse_matrix.cc index 593016ef0..607399442 100644 --- a/src/solver/sparse_matrix.cc +++ b/src/solver/sparse_matrix.cc @@ -1,80 +1,79 @@ /** * @file sparse_matrix.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 - * @date last modification: Mon Nov 16 2015 + * @date last modification: Wed Nov 08 2017 * * @brief implementation of the SparseMatrix 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "dof_manager.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SparseMatrix::SparseMatrix(DOFManager & dof_manager, const MatrixType & matrix_type, const ID & id) : id(id), _dof_manager(dof_manager), matrix_type(matrix_type), size_(dof_manager.getSystemSize()), nb_non_zero(0) { AKANTU_DEBUG_IN(); const auto & comm = _dof_manager.getCommunicator(); this->nb_proc = comm.getNbProc(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix::SparseMatrix(const SparseMatrix & matrix, const ID & id) : SparseMatrix(matrix._dof_manager, matrix.matrix_type, id) { nb_non_zero = matrix.nb_non_zero; } /* -------------------------------------------------------------------------- */ SparseMatrix::~SparseMatrix() = default; /* -------------------------------------------------------------------------- */ Array<Real> & operator*=(Array<Real> & vect, const SparseMatrix & mat) { Array<Real> tmp(vect.size(), vect.getNbComponent(), 0.); mat.matVecMul(vect, tmp); vect.copy(tmp); return vect; } /* -------------------------------------------------------------------------- */ void SparseMatrix::add(const SparseMatrix & B, Real alpha) { B.addMeTo(*this, alpha); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/solver/sparse_matrix.hh b/src/solver/sparse_matrix.hh index 9dc5de8b3..08fe2c837 100644 --- a/src/solver/sparse_matrix.hh +++ b/src/solver/sparse_matrix.hh @@ -1,162 +1,160 @@ - /** * @file sparse_matrix.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 - * @date last modification: Fri Oct 16 2015 + * @date last modification: Tue Feb 20 2018 * * @brief sparse matrix storage class (distributed assembled matrix) * This is a COO format (Coordinate List) * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SPARSE_MATRIX_HH__ #define __AKANTU_SPARSE_MATRIX_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class DOFManager; class TermsToAssemble; } namespace akantu { class SparseMatrix { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseMatrix(DOFManager & dof_manager, const MatrixType & matrix_type, const ID & id = "sparse_matrix"); SparseMatrix(const SparseMatrix & matrix, const ID & id = "sparse_matrix"); virtual ~SparseMatrix(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// remove the existing profile virtual void clearProfile(); /// set the matrix to 0 virtual void clear() = 0; /// add a non-zero element to the profile virtual UInt add(UInt i, UInt j) = 0; /// assemble a local matrix in the sparse one virtual void add(UInt i, UInt j, Real value) = 0; /// save the profil in a file using the MatrixMarket file format virtual void saveProfile(__attribute__((unused)) const std::string &) const { AKANTU_TO_IMPLEMENT(); } /// save the matrix in a file using the MatrixMarket file format virtual void saveMatrix(__attribute__((unused)) const std::string &) const { AKANTU_TO_IMPLEMENT(); }; /// multiply the matrix by a coefficient virtual void mul(Real alpha) = 0; /// add matrices virtual void add(const SparseMatrix & matrix, Real alpha = 1.); /// Equivalent of *gemv in blas virtual void matVecMul(const Array<Real> & x, Array<Real> & y, Real alpha = 1., Real beta = 0.) const = 0; /// modify the matrix to "remove" the blocked dof virtual void applyBoundary(Real block_val = 1.) = 0; /// operator *= SparseMatrix & operator*=(Real alpha) { this->mul(alpha); return *this; } protected: /// This is the revert of add B += \alpha * *this; virtual void addMeTo(SparseMatrix & B, Real alpha) const = 0; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the values at potition i, j virtual inline Real operator()(__attribute__((unused)) UInt i, __attribute__((unused)) UInt j) const { AKANTU_TO_IMPLEMENT(); } /// return the values at potition i, j virtual inline Real & operator()(__attribute__((unused)) UInt i, __attribute__((unused)) UInt j) { AKANTU_TO_IMPLEMENT(); } AKANTU_GET_MACRO(NbNonZero, nb_non_zero, UInt); UInt size() const { return size_; } AKANTU_GET_MACRO(MatrixType, matrix_type, const MatrixType &); virtual UInt getRelease() const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: ID id; /// Underlying dof manager DOFManager & _dof_manager; /// sparce matrix type MatrixType matrix_type; /// Size of the matrix UInt size_; /// number of processors UInt nb_proc; /// number of non zero element UInt nb_non_zero; }; Array<Real> & operator*=(Array<Real> & vect, const SparseMatrix & mat); } // akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "sparse_matrix_inline_impl.cc" #endif /* __AKANTU_SPARSE_MATRIX_HH__ */ diff --git a/src/solver/sparse_matrix_aij.cc b/src/solver/sparse_matrix_aij.cc index acf516e85..cb10f23ae 100644 --- a/src/solver/sparse_matrix_aij.cc +++ b/src/solver/sparse_matrix_aij.cc @@ -1,215 +1,216 @@ /** * @file sparse_matrix_aij.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 18 16:31:23 2015 + * @date creation: Fri Aug 21 2015 + * @date last modification: Mon Dec 04 2017 * * @brief Implementation of the AIJ sparse matrix * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "sparse_matrix_aij.hh" #include "aka_iterators.hh" #include "dof_manager_default.hh" #include "dof_synchronizer.hh" #include "terms_to_assemble.hh" /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SparseMatrixAIJ::SparseMatrixAIJ(DOFManagerDefault & dof_manager, const MatrixType & matrix_type, const ID & id) : SparseMatrix(dof_manager, matrix_type, id), dof_manager(dof_manager), irn(0, 1, id + ":irn"), jcn(0, 1, id + ":jcn"), a(0, 1, id + ":a") {} /* -------------------------------------------------------------------------- */ SparseMatrixAIJ::SparseMatrixAIJ(const SparseMatrixAIJ & matrix, const ID & id) : SparseMatrix(matrix, id), dof_manager(matrix.dof_manager), irn(matrix.irn, true, id + ":irn"), jcn(matrix.jcn, true, id + ":jcn"), a(matrix.a, true, id + ":a") {} /* -------------------------------------------------------------------------- */ SparseMatrixAIJ::~SparseMatrixAIJ() = default; /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::applyBoundary(Real block_val) { AKANTU_DEBUG_IN(); // clang-format off const auto & blocked_dofs = this->dof_manager.getGlobalBlockedDOFs(); for (auto && ij_a : zip(irn, jcn, a)) { UInt ni = this->dof_manager.globalToLocalEquationNumber(std::get<0>(ij_a) - 1); UInt nj = this->dof_manager.globalToLocalEquationNumber(std::get<1>(ij_a) - 1); if (blocked_dofs(ni) || blocked_dofs(nj)) { std::get<2>(ij_a) = std::get<0>(ij_a) != std::get<1>(ij_a) ? 0. : this->dof_manager.isLocalOrMasterDOF(ni) ? block_val : 0.; } } this->value_release++; // clang-format on AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::saveProfile(const std::string & filename) const { AKANTU_DEBUG_IN(); std::ofstream outfile; outfile.open(filename.c_str()); UInt m = this->size_; outfile << "%%MatrixMarket matrix coordinate pattern"; if (this->matrix_type == _symmetric) outfile << " symmetric"; else outfile << " general"; outfile << std::endl; outfile << m << " " << m << " " << this->nb_non_zero << std::endl; for (UInt i = 0; i < this->nb_non_zero; ++i) { outfile << this->irn.storage()[i] << " " << this->jcn.storage()[i] << " 1" << std::endl; } outfile.close(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::saveMatrix(const std::string & filename) const { AKANTU_DEBUG_IN(); // open and set the properties of the stream std::ofstream outfile; outfile.open(filename.c_str()); outfile.precision(std::numeric_limits<Real>::digits10); // write header outfile << "%%MatrixMarket matrix coordinate real"; if (this->matrix_type == _symmetric) outfile << " symmetric"; else outfile << " general"; outfile << std::endl; outfile << this->size_ << " " << this->size_ << " " << this->nb_non_zero << std::endl; // write content for (UInt i = 0; i < this->nb_non_zero; ++i) { outfile << this->irn(i) << " " << this->jcn(i) << " " << this->a(i) << std::endl; } // time to end outfile.close(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::matVecMul(const Array<Real> & x, Array<Real> & y, Real alpha, Real beta) const { AKANTU_DEBUG_IN(); y *= beta; auto i_it = this->irn.begin(); auto j_it = this->jcn.begin(); auto a_it = this->a.begin(); auto a_end = this->a.end(); auto x_it = x.begin_reinterpret(x.size() * x.getNbComponent()); auto y_it = y.begin_reinterpret(x.size() * x.getNbComponent()); for (; a_it != a_end; ++i_it, ++j_it, ++a_it) { Int i = this->dof_manager.globalToLocalEquationNumber(*i_it - 1); Int j = this->dof_manager.globalToLocalEquationNumber(*j_it - 1); const Real & A = *a_it; y_it[i] += alpha * A * x_it[j]; if ((this->matrix_type == _symmetric) && (i != j)) y_it[j] += alpha * A * x_it[i]; } if (this->dof_manager.hasSynchronizer()) this->dof_manager.getSynchronizer().reduceSynchronize<AddOperation>(y); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::copyContent(const SparseMatrix & matrix) { AKANTU_DEBUG_IN(); const auto & mat = dynamic_cast<const SparseMatrixAIJ &>(matrix); AKANTU_DEBUG_ASSERT(nb_non_zero == mat.getNbNonZero(), "The to matrix don't have the same profiles"); memcpy(a.storage(), mat.getA().storage(), nb_non_zero * sizeof(Real)); this->value_release++; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class MatrixType> void SparseMatrixAIJ::addMeToTemplated(MatrixType & B, Real alpha) const { UInt i, j; Real A_ij; for (auto && tuple : zip(irn, jcn, a)) { std::tie(i, j, A_ij) = tuple; B.add(i - 1, j - 1, alpha * A_ij); } } /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::addMeTo(SparseMatrix & B, Real alpha) const { if (auto * B_aij = dynamic_cast<SparseMatrixAIJ *>(&B)) { this->addMeToTemplated<SparseMatrixAIJ>(*B_aij, alpha); } else { // this->addMeToTemplated<SparseMatrix>(*this, alpha); } } /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::mul(Real alpha) { this->a *= alpha; this->value_release++; } /* -------------------------------------------------------------------------- */ void SparseMatrixAIJ::clear() { a.set(0.); this->value_release++; } } // namespace akantu diff --git a/src/solver/sparse_matrix_aij.hh b/src/solver/sparse_matrix_aij.hh index 9c067be24..668927be0 100644 --- a/src/solver/sparse_matrix_aij.hh +++ b/src/solver/sparse_matrix_aij.hh @@ -1,180 +1,182 @@ /** * @file sparse_matrix_aij.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Mon Aug 17 21:22:57 2015 + * @date creation: Mon Dec 13 2010 + * @date last modification: Wed Nov 08 2017 * - * @brief AIJ implementation of the SparseMatrix (this the format used by Mumps) + * @brief AIJ implementation of the SparseMatrix (this the format used by + * Mumps) * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ #include <unordered_map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SPARSE_MATRIX_AIJ_HH__ #define __AKANTU_SPARSE_MATRIX_AIJ_HH__ namespace akantu { class DOFManagerDefault; class TermsToAssemble; } namespace akantu { class SparseMatrixAIJ : public SparseMatrix { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseMatrixAIJ(DOFManagerDefault & dof_manager, const MatrixType & matrix_type, const ID & id = "sparse_matrix_aij"); SparseMatrixAIJ(const SparseMatrixAIJ & matrix, const ID & id = "sparse_matrix_aij"); ~SparseMatrixAIJ() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// remove the existing profile inline void clearProfile() override; /// add a non-zero element inline UInt add(UInt i, UInt j) override; /// set the matrix to 0 void clear() override; /// assemble a local matrix in the sparse one inline void add(UInt i, UInt j, Real value) override; /// set the size of the matrix void resize(UInt size) { this->size_ = size; } /// modify the matrix to "remove" the blocked dof void applyBoundary(Real block_val = 1.) override; /// save the profil in a file using the MatrixMarket file format void saveProfile(const std::string & filename) const override; /// save the matrix in a file using the MatrixMarket file format void saveMatrix(const std::string & filename) const override; /// copy assuming the profile are the same virtual void copyContent(const SparseMatrix & matrix); /// multiply the matrix by a scalar void mul(Real alpha) override; /// add matrix *this += B // virtual void add(const SparseMatrix & matrix, Real alpha); /// Equivalent of *gemv in blas void matVecMul(const Array<Real> & x, Array<Real> & y, Real alpha = 1., Real beta = 0.) const override; /* ------------------------------------------------------------------------ */ /// accessor to A_{ij} - if (i, j) not present it returns 0 inline Real operator()(UInt i, UInt j) const override; /// accessor to A_{ij} - if (i, j) not present it fails, (i, j) should be /// first added to the profile inline Real & operator()(UInt i, UInt j) override; protected: /// This is the revert of add B += \alpha * *this; void addMeTo(SparseMatrix & B, Real alpha) const override; private: /// This is just to inline the addToMatrix function template <class MatrixType> void addMeToTemplated(MatrixType & B, Real alpha) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(IRN, irn, const Array<Int> &); AKANTU_GET_MACRO(JCN, jcn, const Array<Int> &); AKANTU_GET_MACRO(A, a, const Array<Real> &); /// The release changes at each call of a function that changes the profile, /// it in increasing but could overflow so it should be checked as /// (my_release != release) and not as (my_release < release) AKANTU_GET_MACRO(ProfileRelease, profile_release, UInt); AKANTU_GET_MACRO(ValueRelease, value_release, UInt); UInt getRelease() const override { return value_release; } protected: using KeyCOO = std::pair<UInt, UInt>; using coordinate_list_map = std::unordered_map<KeyCOO, UInt>; /// get the pair corresponding to (i, j) inline KeyCOO key(UInt i, UInt j) const { if (this->matrix_type == _symmetric && (i > j)) return std::make_pair(j, i); return std::make_pair(i, j); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: DOFManagerDefault & dof_manager; /// row indexes Array<Int> irn; /// column indexes Array<Int> jcn; /// values : A[k] = Matrix[irn[k]][jcn[k]] Array<Real> a; /// Profile release UInt profile_release{1}; /// Value release UInt value_release{1}; /// map for (i, j) -> k correspondence coordinate_list_map irn_jcn_k; }; } // akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "sparse_matrix_aij_inline_impl.cc" #endif /* __AKANTU_SPARSE_MATRIX_AIJ_HH__ */ diff --git a/src/solver/sparse_matrix_aij_inline_impl.cc b/src/solver/sparse_matrix_aij_inline_impl.cc index 2c6ee5081..d9d8f8774 100644 --- a/src/solver/sparse_matrix_aij_inline_impl.cc +++ b/src/solver/sparse_matrix_aij_inline_impl.cc @@ -1,116 +1,118 @@ /** * @file sparse_matrix_aij_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Aug 18 00:42:45 2015 + * @date creation: Fri Aug 21 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Implementation of inline functions of SparseMatrixAIJ * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "sparse_matrix_aij.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SPARSE_MATRIX_AIJ_INLINE_IMPL_CC__ #define __AKANTU_SPARSE_MATRIX_AIJ_INLINE_IMPL_CC__ namespace akantu { inline UInt SparseMatrixAIJ::add(UInt i, UInt j) { KeyCOO jcn_irn = this->key(i, j); auto it = this->irn_jcn_k.find(jcn_irn); if (!(it == this->irn_jcn_k.end())) return it->second; if (i + 1 > this->size_) this->size_ = i + 1; if (j + 1 > this->size_) this->size_ = j + 1; this->irn.push_back(i + 1); this->jcn.push_back(j + 1); this->a.push_back(0.); this->irn_jcn_k[jcn_irn] = this->nb_non_zero; (this->nb_non_zero)++; this->profile_release++; this->value_release++; return (this->nb_non_zero - 1); } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::clearProfile() { SparseMatrix::clearProfile(); this->irn_jcn_k.clear(); this->irn.resize(0); this->jcn.resize(0); this->a.resize(0); this->size_ = 0; this->profile_release++; this->value_release++; } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::add(UInt i, UInt j, Real value) { UInt idx = this->add(i, j); this->a(idx) += value; this->value_release++; } /* -------------------------------------------------------------------------- */ inline Real SparseMatrixAIJ::operator()(UInt i, UInt j) const { KeyCOO jcn_irn = this->key(i, j); auto irn_jcn_k_it = this->irn_jcn_k.find(jcn_irn); if (irn_jcn_k_it == this->irn_jcn_k.end()) return 0.; return this->a(irn_jcn_k_it->second); } /* -------------------------------------------------------------------------- */ inline Real & SparseMatrixAIJ::operator()(UInt i, UInt j) { KeyCOO jcn_irn = this->key(i, j); auto irn_jcn_k_it = this->irn_jcn_k.find(jcn_irn); AKANTU_DEBUG_ASSERT(irn_jcn_k_it != this->irn_jcn_k.end(), "Couple (i,j) = (" << i << "," << j << ") does not exist in the profile"); // it may change the profile so it is considered as a change this->value_release++; return this->a(irn_jcn_k_it->second); } } // namespace akantu #endif /* __AKANTU_SPARSE_MATRIX_AIJ_INLINE_IMPL_CC__ */ diff --git a/src/solver/sparse_matrix_inline_impl.cc b/src/solver/sparse_matrix_inline_impl.cc index dc1a84948..8a90f0860 100644 --- a/src/solver/sparse_matrix_inline_impl.cc +++ b/src/solver/sparse_matrix_inline_impl.cc @@ -1,37 +1,36 @@ /** * @file sparse_matrix_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 - * @date last modification: Tue Aug 18 2015 + * @date last modification: Mon Jun 19 2017 * * @brief implementation of inline methods of the SparseMatrix 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ namespace akantu { inline void SparseMatrix::clearProfile() { this->nb_non_zero = 0; } } // akantu diff --git a/src/solver/sparse_matrix_petsc.cc b/src/solver/sparse_matrix_petsc.cc index 906c4056e..ab5c6dbad 100644 --- a/src/solver/sparse_matrix_petsc.cc +++ b/src/solver/sparse_matrix_petsc.cc @@ -1,402 +1,405 @@ /** - * @file petsc_matrix.cc - * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> - * @date Mon Jul 21 17:40:41 2014 + * @file sparse_matrix_petsc.cc + * + * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> + * + * @date creation: Mon Dec 13 2010 + * @date last modification: Sat Feb 03 2018 * * @brief Implementation of PETSc matrix class * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "sparse_matrix_petsc.hh" #include "dof_manager_petsc.hh" #include "mpi_type_wrapper.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ #include <cstring> #include <petscsys.h> /* -------------------------------------------------------------------------- */ namespace akantu { #if not defined(PETSC_CLANGUAGE_CXX) int aka_PETScError(int ierr) { CHKERRQ(ierr); return 0; } #endif /* -------------------------------------------------------------------------- */ SparseMatrixPETSc::SparseMatrixPETSc(DOFManagerPETSc & dof_manager, const MatrixType & sparse_matrix_type, const ID & id, const MemoryID & memory_id) : SparseMatrix(dof_manager, matrix_type, id, memory_id), dof_manager(dof_manager), d_nnz(0, 1, "dnnz"), o_nnz(0, 1, "onnz"), first_global_index(0) { AKANTU_DEBUG_IN(); PetscErrorCode ierr; // create the PETSc matrix object ierr = MatCreate(PETSC_COMM_WORLD, &this->mat); CHKERRXX(ierr); /** * Set the matrix type * @todo PETSc does currently not support a straightforward way to * apply Dirichlet boundary conditions for MPISBAIJ * matrices. Therefore always the entire matrix is allocated. It * would be possible to use MATSBAIJ for sequential matrices in case * memory becomes critical. Also, block matrices would give a much * better performance. Modify this in the future! */ ierr = MatSetType(this->mat, MATAIJ); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrixPETSc::~SparseMatrixPETSc() { AKANTU_DEBUG_IN(); /// destroy all the PETSc data structures used for this matrix PetscErrorCode ierr; ierr = MatDestroy(&this->mat); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * With this method each processor computes the dimensions of the * local matrix, i.e. the part of the global matrix it is storing. * @param dof_synchronizer dof synchronizer that maps the local * dofs to the global dofs and the equation numbers, i.e., the * position at which the dof is assembled in the matrix */ void SparseMatrixPETSc::setSize() { AKANTU_DEBUG_IN(); // PetscErrorCode ierr; /// find the number of dofs corresponding to master or local nodes UInt nb_dofs = this->dof_manager.getLocalSystemSize(); // UInt nb_local_master_dofs = 0; /// create array to store the global equation number of all local and master /// dofs Array<Int> local_master_eq_nbs(nb_dofs); Array<Int>::scalar_iterator it_eq_nb = local_master_eq_nbs.begin(); throw; /// get the pointer to the global equation number array // Int * eq_nb_val = // this->dof_synchronizer->getGlobalDOFEquationNumbers().storage(); // for (UInt i = 0; i < nb_dofs; ++i) { // if (this->dof_synchronizer->isLocalOrMasterDOF(i)) { // *it_eq_nb = eq_nb_val[i]; // ++it_eq_nb; // ++nb_local_master_dofs; // } // } // local_master_eq_nbs.resize(nb_local_master_dofs); // /// set the local size // this->local_size = nb_local_master_dofs; // /// resize PETSc matrix // #if defined(AKANTU_USE_MPI) // ierr = MatSetSizes(this->petsc_matrix_wrapper->mat, this->local_size, // this->local_size, this->size, this->size); // CHKERRXX(ierr); // #else // ierr = MatSetSizes(this->petsc_matrix_wrapper->mat, this->local_size, // this->local_size); // CHKERRXX(ierr); // #endif // /// create mapping from akantu global numbering to petsc global numbering // this->createGlobalAkantuToPETScMap(local_master_eq_nbs.storage()); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This method generates a mapping from the global Akantu equation * numbering to the global PETSc dof ordering * @param local_master_eq_nbs_ptr Int pointer to the array of equation * numbers of all local or master dofs, i.e. the row indices of the * local matrix */ void SparseMatrixPETSc::createGlobalAkantuToPETScMap( Int * local_master_eq_nbs_ptr) { AKANTU_DEBUG_IN(); PetscErrorCode ierr; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt rank = comm.whoAmI(); // initialize vector to store the number of local and master nodes that are // assigned to each processor Vector<UInt> master_local_ndofs_per_proc(nb_proc); /// store the nb of master and local dofs on each processor master_local_ndofs_per_proc(rank) = this->local_size; /// exchange the information among all processors comm.allGather(master_local_ndofs_per_proc.storage(), 1); /// each processor creates a map for his akantu global dofs to the /// corresponding petsc global dofs /// determine the PETSc-index for the first dof on each processor for (UInt i = 0; i < rank; ++i) { this->first_global_index += master_local_ndofs_per_proc(i); } /// create array for petsc ordering Array<Int> petsc_dofs(this->local_size); Array<Int>::scalar_iterator it_petsc_dofs = petsc_dofs.begin(); for (Int i = this->first_global_index; i < this->first_global_index + this->local_size; ++i, ++it_petsc_dofs) { *it_petsc_dofs = i; } ierr = AOCreateBasic(PETSC_COMM_WORLD, this->local_size, local_master_eq_nbs_ptr, petsc_dofs.storage(), &(this->ao)); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Method to save the nonzero pattern and the values stored at each position * @param filename name of the file in which the information will be stored */ void SparseMatrixPETSc::saveMatrix(const std::string & filename) const { AKANTU_DEBUG_IN(); PetscErrorCode ierr; /// create Petsc viewer PetscViewer viewer; ierr = PetscViewerASCIIOpen(PETSC_COMM_WORLD, filename.c_str(), &viewer); CHKERRXX(ierr); /// set the format PetscViewerSetFormat(viewer, PETSC_VIEWER_DEFAULT); CHKERRXX(ierr); /// save the matrix /// @todo Write should be done in serial -> might cause problems ierr = MatView(this->mat, viewer); CHKERRXX(ierr); /// destroy the viewer ierr = PetscViewerDestroy(&viewer); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Method to add an Akantu sparse matrix to the PETSc matrix * @param matrix Akantu sparse matrix to be added * @param alpha the factor specifying how many times the matrix should be added */ // void SparseMatrixPETSc::add(const SparseMatrix & matrix, Real alpha) { // PetscErrorCode ierr; // // AKANTU_DEBUG_ASSERT(nb_non_zero == matrix.getNbNonZero(), // // "The two matrix don't have the same profiles"); // Real val_to_add = 0; // Array<Int> index(2); // for (UInt n = 0; n < matrix.getNbNonZero(); ++n) { // UInt mat_to_add_offset = matrix.getOffset(); // index(0) = matrix.getIRN()(n) - mat_to_add_offset; // index(1) = matrix.getJCN()(n) - mat_to_add_offset; // AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index.storage()); // if (this->sparse_matrix_type == _symmetric && index(0) > index(1)) // std::swap(index(0), index(1)); // val_to_add = matrix.getA()(n) * alpha; // /// MatSetValue might be very slow for MATBAIJ, might need to use // /// MatSetValuesBlocked // ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(0), index(1), // val_to_add, ADD_VALUES); // CHKERRXX(ierr); // /// chek if sparse matrix to be added is symmetric. In this case // /// the value also needs to be added at the transposed location in // /// the matrix because PETSc is using the full profile, also for // symmetric // /// matrices // if (matrix.getSparseMatrixType() == _symmetric && index(0) != index(1)) // ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(1), index(0), // val_to_add, ADD_VALUES); // CHKERRXX(ierr); // } // this->performAssembly(); // } /* -------------------------------------------------------------------------- */ /** * Method to add another PETSc matrix to this PETSc matrix * @param matrix PETSc matrix to be added * @param alpha the factor specifying how many times the matrix should be added */ void SparseMatrixPETSc::add(const SparseMatrixPETSc & matrix, Real alpha) { PetscErrorCode ierr; ierr = MatAXPY(this->mat, alpha, matrix.mat, SAME_NONZERO_PATTERN); CHKERRXX(ierr); this->performAssembly(); } /* -------------------------------------------------------------------------- */ /** * MatSetValues() generally caches the values. The matrix is ready to * use only after MatAssemblyBegin() and MatAssemblyEnd() have been * called. (http://www.mcs.anl.gov/petsc/) */ void SparseMatrixPETSc::performAssembly() { this->beginAssembly(); this->endAssembly(); } /* -------------------------------------------------------------------------- */ void SparseMatrixPETSc::beginAssembly() { PetscErrorCode ierr; ierr = MatAssemblyBegin(this->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr); ierr = MatAssemblyEnd(this->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr); } /* -------------------------------------------------------------------------- */ void SparseMatrixPETSc::endAssembly() { PetscErrorCode ierr; ierr = MatAssemblyEnd(this->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr); } /* -------------------------------------------------------------------------- */ /// access K(i, j). Works only for dofs on this processor!!!! Real SparseMatrixPETSc::operator()(UInt i, UInt j) const { AKANTU_DEBUG_IN(); // AKANTU_DEBUG_ASSERT(this->dof_synchronizer->isLocalOrMasterDOF(i) && // this->dof_synchronizer->isLocalOrMasterDOF(j), // "Operator works only for dofs on this processor"); // Array<Int> index(2, 1); // index(0) = this->dof_synchronizer->getDOFGlobalID(i); // index(1) = this->dof_synchronizer->getDOFGlobalID(j); // AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index.storage()); // Real value = 0; // PetscErrorCode ierr; // /// @todo MatGetValue might be very slow for MATBAIJ, might need to use // /// MatGetValuesBlocked // ierr = MatGetValues(this->petsc_matrix_wrapper->mat, 1, &index(0), 1, // &index(1), &value); // CHKERRXX(ierr); // AKANTU_DEBUG_OUT(); // return value; return 0.; } /* -------------------------------------------------------------------------- */ /** * Apply Dirichlet boundary conditions by zeroing the rows and columns which * correspond to blocked dofs * @param boundary array of booleans which are true if the dof at this position * is blocked * @param block_val the value in the diagonal entry of blocked rows */ void SparseMatrixPETSc::applyBoundary(const Array<bool> & boundary, Real block_val) { AKANTU_DEBUG_IN(); // PetscErrorCode ierr; // /// get the global equation numbers to find the rows that need to be zeroed // /// for the blocked dofs // Int * eq_nb_val = // dof_synchronizer->getGlobalDOFEquationNumbers().storage(); // /// every processor calls the MatSetZero() only for his local or master // dofs. // /// This assures that not two processors or more try to zero the same row // UInt nb_component = boundary.getNbComponent(); // UInt size = boundary.size(); // Int nb_blocked_local_master_eq_nb = 0; // Array<Int> blocked_local_master_eq_nb(this->local_size); // Int * blocked_lm_eq_nb_ptr = blocked_local_master_eq_nb.storage(); // for (UInt i = 0; i < size; ++i) { // for (UInt j = 0; j < nb_component; ++j) { // UInt local_dof = i * nb_component + j; // if (boundary(i, j) == true && // this->dof_synchronizer->isLocalOrMasterDOF(local_dof)) { // Int global_eq_nb = *eq_nb_val; // *blocked_lm_eq_nb_ptr = global_eq_nb; // ++nb_blocked_local_master_eq_nb; // ++blocked_lm_eq_nb_ptr; // } // ++eq_nb_val; // } // } // blocked_local_master_eq_nb.resize(nb_blocked_local_master_eq_nb); // ierr = AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, // nb_blocked_local_master_eq_nb, // blocked_local_master_eq_nb.storage()); // CHKERRXX(ierr); // ierr = MatZeroRowsColumns( // this->petsc_matrix_wrapper->mat, nb_blocked_local_master_eq_nb, // blocked_local_master_eq_nb.storage(), block_val, 0, 0); // CHKERRXX(ierr); // this->performAssembly(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// set all entries to zero while keeping the same nonzero pattern void SparseMatrixPETSc::clear() { MatZeroEntries(this->mat); } } // akantu diff --git a/src/solver/sparse_matrix_petsc.hh b/src/solver/sparse_matrix_petsc.hh index fafa3b64c..89597ebd5 100644 --- a/src/solver/sparse_matrix_petsc.hh +++ b/src/solver/sparse_matrix_petsc.hh @@ -1,142 +1,141 @@ /** - * @file petsc_matrix.hh + * @file sparse_matrix_petsc.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Fri Aug 21 2015 + * @date last modification: Tue Feb 06 2018 * * @brief Interface for PETSc matrices * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PETSC_MATRIX_HH__ #define __AKANTU_PETSC_MATRIX_HH__ /* -------------------------------------------------------------------------- */ #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ #include <petscao.h> #include <petscmat.h> /* -------------------------------------------------------------------------- */ namespace akantu { class DOFManagerPETSc; } namespace akantu { class SparseMatrixPETSc : public SparseMatrix { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseMatrixPETSc(DOFManagerPETSc & dof_manager, const MatrixType & matrix_type, const ID & id = "sparse_matrix", const MemoryID & memory_id = 0); SparseMatrixPETSc(const SparseMatrix & matrix, const ID & id = "sparse_matrix_petsc", const MemoryID & memory_id = 0); virtual ~SparseMatrixPETSc(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// set the matrix to 0 virtual void clear(); /// modify the matrix to "remove" the blocked dof virtual void applyBoundary(const Array<bool> & boundary, Real block_val = 1.); /// save the matrix in a ASCII file format virtual void saveMatrix(const std::string & filename) const; /// add a sparse matrix assuming the profile are the same virtual void add(const SparseMatrix & matrix, Real alpha); /// add a petsc matrix assuming the profile are the same virtual void add(const SparseMatrixPETSc & matrix, Real alpha); Real operator()(UInt i, UInt j) const; protected: typedef std::pair<UInt, UInt> KeyCOO; inline KeyCOO key(UInt i, UInt j) const { return std::make_pair(i, j); } private: virtual void destroyInternalData(); /// set the size of the PETSc matrix void setSize(); void createGlobalAkantuToPETScMap(Int * local_master_eq_nbs_ptr); void createLocalAkantuToPETScMap(); /// start to assemble the matrix void beginAssembly(); /// finishes to assemble the matrix void endAssembly(); /// perform the assembly stuff from petsc void performAssembly(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(PETScMat, mat, const Mat &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: // DOFManagerPETSc that contains the numbering for petsc DOFManagerPETSc & dof_manager; /// store the PETSc matrix Mat mat; AO ao; /// size of the diagonal part of the matrix partition Int local_size; /// number of nonzeros in every row of the diagonal part Array<Int> d_nnz; /// number of nonzeros in every row of the off-diagonal part Array<Int> o_nnz; /// the global index of the first local row Int first_global_index; /// bool to indicate if the matrix data has been initialized by calling /// MatCreate bool is_petsc_matrix_initialized; }; } // akantu #endif /* __AKANTU_PETSC_MATRIX_HH__ */ diff --git a/src/solver/sparse_solver.cc b/src/solver/sparse_solver.cc index 81e6a18f8..9fe6be43a 100644 --- a/src/solver/sparse_solver.cc +++ b/src/solver/sparse_solver.cc @@ -1,85 +1,84 @@ /** - * @file solver.cc + * @file sparse_solver.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Fri Dec 08 2017 * * @brief Solver interface 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "sparse_solver.hh" #include "communicator.hh" #include "dof_manager.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SparseSolver::SparseSolver(DOFManager & dof_manager, const ID & matrix_id, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), Parsable(ParserType::_solver, id), _dof_manager(dof_manager), matrix_id(matrix_id), communicator(dof_manager.getCommunicator()) { AKANTU_DEBUG_IN(); // OK this is fishy... this->communicator.registerEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseSolver::~SparseSolver() { AKANTU_DEBUG_IN(); // this->destroyInternalData(); this->communicator.unregisterEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolver::beforeStaticSolverDestroy() { AKANTU_DEBUG_IN(); try { this->destroyInternalData(); } catch (...) { } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolver::createSynchronizerRegistry() { // this->synch_registry = new SynchronizerRegistry(this); } void SparseSolver::onCommunicatorFinalize() { this->destroyInternalData(); } } // akantu diff --git a/src/solver/sparse_solver.hh b/src/solver/sparse_solver.hh index 7c79df5a1..5b042f3c3 100644 --- a/src/solver/sparse_solver.hh +++ b/src/solver/sparse_solver.hh @@ -1,130 +1,130 @@ /** * @file sparse_solver.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> + * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Wed Jan 24 2018 * * @brief interface for solvers * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "communicator_event_handler.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLVER_HH__ #define __AKANTU_SOLVER_HH__ namespace akantu { enum SolverParallelMethod { _not_parallel, _fully_distributed, _master_slave_distributed }; class DOFManager; } namespace akantu { class SparseSolver : protected Memory, public Parsable, public CommunicatorEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseSolver(DOFManager & dof_manager, const ID & matrix_id, const ID & id = "solver", const MemoryID & memory_id = 0); ~SparseSolver() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver virtual void initialize() = 0; virtual void analysis(){}; virtual void factorize(){}; virtual void solve(){}; protected: virtual void destroyInternalData(){}; public: virtual void beforeStaticSolverDestroy(); void createSynchronizerRegistry(); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: void onCommunicatorFinalize() override; // inline virtual UInt getNbDataForDOFs(const Array<UInt> & dofs, // SynchronizationTag tag) const; // inline virtual void packDOFData(CommunicationBuffer & buffer, // const Array<UInt> & dofs, // SynchronizationTag tag) const; // inline virtual void unpackDOFData(CommunicationBuffer & buffer, // const Array<UInt> & dofs, // SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// manager handling the dofs for this SparseMatrix solver DOFManager & _dof_manager; /// The id of the associated matrix ID matrix_id; /// How to parallelize the solve SolverParallelMethod parallel_method; /// Communicator used by the solver Communicator & communicator; }; namespace debug { class SingularMatrixException : public Exception { public: SingularMatrixException(const SparseMatrix & matrix) : Exception("Solver encountered singular matrix"), matrix(matrix) {} const SparseMatrix & matrix; }; } } // akantu #endif /* __AKANTU_SOLVER_HH__ */ diff --git a/src/solver/sparse_solver_inline_impl.cc b/src/solver/sparse_solver_inline_impl.cc index 98e3a7bc9..a2890274e 100644 --- a/src/solver/sparse_solver_inline_impl.cc +++ b/src/solver/sparse_solver_inline_impl.cc @@ -1,83 +1,87 @@ /** - * @file solver_inline_impl.cc - * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> - * @date Thu Nov 13 14:43:41 2014 + * @file sparse_solver_inline_impl.cc + * + * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> + * + * @date creation: Mon Dec 13 2010 + * @date last modification: Sun Aug 13 2017 * * @brief implementation of solver inline functions * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ // inline UInt Solver::getNbDataForDOFs(const Array<UInt> & dofs, // SynchronizationTag tag) const { // AKANTU_DEBUG_IN(); // UInt size = 0; // switch(tag) { // case _gst_solver_solution: { // size += dofs.size() * sizeof(Real); // break; // } // default: { } // } // AKANTU_DEBUG_OUT(); // return size; // } // /* -------------------------------------------------------------------------- // */ // inline void Solver::packDOFData(CommunicationBuffer & buffer, // const Array<UInt> & dofs, // SynchronizationTag tag) const { // AKANTU_DEBUG_IN(); // switch(tag) { // case _gst_solver_solution: { // packDOFDataHelper(*solution, buffer, dofs); // break; // } // default: { // } // } // AKANTU_DEBUG_OUT(); // } // /* -------------------------------------------------------------------------- // */ // inline void Solver::unpackDOFData(CommunicationBuffer & buffer, // const Array<UInt> & dofs, // SynchronizationTag tag) { // AKANTU_DEBUG_IN(); // switch(tag) { // case _gst_solver_solution: { // unpackDOFDataHelper(*solution, buffer, dofs); // break; // } // default: { // } // } // AKANTU_DEBUG_OUT(); // } diff --git a/src/solver/sparse_solver_mumps.cc b/src/solver/sparse_solver_mumps.cc index 918d89f09..63ea0148d 100644 --- a/src/solver/sparse_solver_mumps.cc +++ b/src/solver/sparse_solver_mumps.cc @@ -1,446 +1,445 @@ /** * @file sparse_solver_mumps.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Tue Feb 20 2018 * * @brief implem of SparseSolverMumps 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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @subsection Ctrl_param Control parameters * * ICNTL(1), * ICNTL(2), * ICNTL(3) : output streams for error, diagnostics, and global messages * * ICNTL(4) : verbose level : 0 no message - 4 all messages * * ICNTL(5) : type of matrix, 0 assembled, 1 elementary * * ICNTL(6) : control the permutation and scaling(default 7) see mumps doc for * more information * * ICNTL(7) : determine the pivot order (default 7) see mumps doc for more * information * * ICNTL(8) : describe the scaling method used * * ICNTL(9) : 1 solve A x = b, 0 solve At x = b * * ICNTL(10) : number of iterative refinement when NRHS = 1 * * ICNTL(11) : > 0 return statistics * * ICNTL(12) : only used for SYM = 2, ordering strategy * * ICNTL(13) : * * ICNTL(14) : percentage of increase of the estimated working space * * ICNTL(15-17) : not used * * ICNTL(18) : only used if ICNTL(5) = 0, 0 matrix centralized, 1 structure on * host and mumps give the mapping, 2 structure on host and distributed matrix * for facto, 3 distributed matrix * * ICNTL(19) : > 0, Shur complement returned * * ICNTL(20) : 0 rhs dense, 1 rhs sparse * * ICNTL(21) : 0 solution in rhs, 1 solution distributed in ISOL_loc and SOL_loc * allocated by user * * ICNTL(22) : 0 in-core, 1 out-of-core * * ICNTL(23) : maximum memory allocatable by mumps pre proc * * ICNTL(24) : controls the detection of "null pivot rows" * * ICNTL(25) : * * ICNTL(26) : * * ICNTL(27) : * * ICNTL(28) : 0 automatic choice, 1 sequential analysis, 2 parallel analysis * * ICNTL(29) : 0 automatic choice, 1 PT-Scotch, 2 ParMetis */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dof_manager_default.hh" #include "dof_synchronizer.hh" #include "sparse_matrix_aij.hh" #if defined(AKANTU_USE_MPI) #include "mpi_communicator_data.hh" #endif #include "sparse_solver_mumps.hh" /* -------------------------------------------------------------------------- */ // static std::ostream & operator <<(std::ostream & stream, const DMUMPS_STRUC_C // & _this) { // stream << "DMUMPS Data [" << std::endl; // stream << " + job : " << _this.job << std::endl; // stream << " + par : " << _this.par << std::endl; // stream << " + sym : " << _this.sym << std::endl; // stream << " + comm_fortran : " << _this.comm_fortran << std::endl; // stream << " + nz : " << _this.nz << std::endl; // stream << " + irn : " << _this.irn << std::endl; // stream << " + jcn : " << _this.jcn << std::endl; // stream << " + nz_loc : " << _this.nz_loc << std::endl; // stream << " + irn_loc : " << _this.irn_loc << std::endl; // stream << " + jcn_loc : " << _this.jcn_loc << std::endl; // stream << "]"; // return stream; // } namespace akantu { /* -------------------------------------------------------------------------- */ SparseSolverMumps::SparseSolverMumps(DOFManagerDefault & dof_manager, const ID & matrix_id, const ID & id, const MemoryID & memory_id) : SparseSolver(dof_manager, matrix_id, id, memory_id), dof_manager(dof_manager), master_rhs_solution(0, 1) { AKANTU_DEBUG_IN(); this->prank = communicator.whoAmI(); #ifdef AKANTU_USE_MPI this->parallel_method = _fully_distributed; #else // AKANTU_USE_MPI this->parallel_method = _not_parallel; #endif // AKANTU_USE_MPI AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseSolverMumps::~SparseSolverMumps() { AKANTU_DEBUG_IN(); mumpsDataDestroy(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::mumpsDataDestroy() { if (this->is_initialized) { this->mumps_data.job = _smj_destroy; // destroy dmumps_c(&this->mumps_data); this->is_initialized = false; } } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::destroyInternalData() { mumpsDataDestroy(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::checkInitialized() { if (this->is_initialized) return; this->initialize(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::setOutputLevel() { // Output setup icntl(1) = 0; // error output icntl(2) = 0; // diagnostics output icntl(3) = 0; // information icntl(4) = 0; #if !defined(AKANTU_NDEBUG) DebugLevel dbg_lvl = debug::debugger.getDebugLevel(); if (AKANTU_DEBUG_TEST(dblDump)) { strcpy(this->mumps_data.write_problem, "mumps_matrix.mtx"); } // clang-format off icntl(1) = (dbg_lvl >= dblWarning) ? 6 : 0; icntl(3) = (dbg_lvl >= dblInfo) ? 6 : 0; icntl(2) = (dbg_lvl >= dblTrace) ? 6 : 0; icntl(4) = dbg_lvl >= dblDump ? 4 : dbg_lvl >= dblTrace ? 3 : dbg_lvl >= dblInfo ? 2 : dbg_lvl >= dblWarning ? 1 : 0; // clang-format on #endif } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::initMumpsData() { auto & A = dof_manager.getMatrix(matrix_id); // Default Scaling icntl(8) = 77; // Assembled matrix icntl(5) = 0; /// Default centralized dense second member icntl(20) = 0; icntl(21) = 0; // automatic choice for analysis icntl(28) = 0; UInt size = A.size(); if (prank == 0) { this->master_rhs_solution.resize(size); } this->mumps_data.nz_alloc = 0; this->mumps_data.n = size; switch (this->parallel_method) { case _fully_distributed: icntl(18) = 3; // fully distributed this->mumps_data.nz_loc = A.getNbNonZero(); this->mumps_data.irn_loc = A.getIRN().storage(); this->mumps_data.jcn_loc = A.getJCN().storage(); break; case _not_parallel: case _master_slave_distributed: icntl(18) = 0; // centralized if (prank == 0) { this->mumps_data.nz = A.getNbNonZero(); this->mumps_data.irn = A.getIRN().storage(); this->mumps_data.jcn = A.getJCN().storage(); } else { this->mumps_data.nz = 0; this->mumps_data.irn = nullptr; this->mumps_data.jcn = nullptr; } break; default: AKANTU_ERROR("This case should not happen!!"); } } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::initialize() { AKANTU_DEBUG_IN(); this->mumps_data.par = 1; // The host is part of computations switch (this->parallel_method) { case _not_parallel: break; case _master_slave_distributed: this->mumps_data.par = 0; // The host is not part of the computations /* FALLTHRU */ /* [[fallthrough]]; un-comment when compiler will get it */ case _fully_distributed: #ifdef AKANTU_USE_MPI const auto & mpi_data = dynamic_cast<const MPICommunicatorData &>( communicator.getCommunicatorData()); MPI_Comm mpi_comm = mpi_data.getMPICommunicator(); this->mumps_data.comm_fortran = MPI_Comm_c2f(mpi_comm); #else AKANTU_ERROR( "You cannot use parallel method to solve without activating MPI"); #endif break; } const auto & A = dof_manager.getMatrix(matrix_id); this->mumps_data.sym = 2 * (A.getMatrixType() == _symmetric); this->prank = communicator.whoAmI(); this->setOutputLevel(); this->mumps_data.job = _smj_initialize; // initialize dmumps_c(&this->mumps_data); this->setOutputLevel(); this->is_initialized = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::analysis() { AKANTU_DEBUG_IN(); initMumpsData(); this->mumps_data.job = _smj_analyze; // analyze dmumps_c(&this->mumps_data); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::factorize() { AKANTU_DEBUG_IN(); auto & A = dof_manager.getMatrix(matrix_id); if (parallel_method == _fully_distributed) this->mumps_data.a_loc = A.getA().storage(); else { if (prank == 0) this->mumps_data.a = A.getA().storage(); } this->mumps_data.job = _smj_factorize; // factorize dmumps_c(&this->mumps_data); this->printError(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::solve(Array<Real> & x, const Array<Real> & b) { auto & synch = this->dof_manager.getSynchronizer(); if (this->prank == 0) { this->master_rhs_solution.resize(this->dof_manager.getSystemSize()); synch.gather(b, this->master_rhs_solution); } else { synch.gather(b); } this->solveInternal(); if (this->prank == 0) { synch.scatter(x, this->master_rhs_solution); } else { synch.scatter(x); } } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::solve() { this->master_rhs_solution.copy(this->dof_manager.getGlobalResidual()); this->solveInternal(); this->dof_manager.setGlobalSolution(this->master_rhs_solution); this->dof_manager.splitSolutionPerDOFs(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::solveInternal() { AKANTU_DEBUG_IN(); this->checkInitialized(); const auto & A = dof_manager.getMatrix(matrix_id); this->setOutputLevel(); if (this->last_profile_release != A.getProfileRelease()) { this->analysis(); this->last_profile_release = A.getProfileRelease(); } if (AKANTU_DEBUG_TEST(dblDump)) { std::stringstream sstr; sstr << prank << ".mtx"; A.saveMatrix("solver_mumps" + sstr.str()); } if (this->last_value_release != A.getValueRelease()) { this->factorize(); this->last_value_release = A.getValueRelease(); } if (prank == 0) { this->mumps_data.rhs = this->master_rhs_solution.storage(); } this->mumps_data.job = _smj_solve; // solve dmumps_c(&this->mumps_data); this->printError(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::printError() { Vector<Int> _info_v(2); _info_v[0] = info(1); // to get errors _info_v[1] = -info(1); // to get warnings dof_manager.getCommunicator().allReduce(_info_v, SynchronizerOperation::_min); _info_v[1] = -_info_v[1]; if (_info_v[0] < 0) { // < 0 is an error switch (_info_v[0]) { case -10: AKANTU_CUSTOM_EXCEPTION( debug::SingularMatrixException(dof_manager.getMatrix(matrix_id))); break; case -9: { icntl(14) += 10; if (icntl(14) != 90) { // std::cout << "Dynamic memory increase of 10%" << std::endl; AKANTU_DEBUG_WARNING("MUMPS dynamic memory is insufficient it will be " "increased allowed to use 10% more"); // change releases to force a recompute this->last_value_release--; this->last_profile_release--; this->solve(); } else { AKANTU_ERROR("The MUMPS workarray is too small INFO(2)=" << info(2) << "No further increase possible"); } break; } default: AKANTU_ERROR("Error in mumps during solve process, check mumps " "user guide INFO(1) = " << _info_v[1]); } } else if (_info_v[1] > 0) { AKANTU_DEBUG_WARNING("Warning in mumps during solve process, check mumps " "user guide INFO(1) = " << _info_v[1]); } } } // akantu diff --git a/src/solver/sparse_solver_mumps.hh b/src/solver/sparse_solver_mumps.hh index 23ec34a6b..af401c7e1 100644 --- a/src/solver/sparse_solver_mumps.hh +++ b/src/solver/sparse_solver_mumps.hh @@ -1,158 +1,157 @@ /** * @file sparse_solver_mumps.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Sun Dec 03 2017 * * @brief Solver class implementation for the mumps solver * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "sparse_solver.hh" /* -------------------------------------------------------------------------- */ #include <dmumps_c.h> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLVER_MUMPS_HH__ #define __AKANTU_SOLVER_MUMPS_HH__ namespace akantu { class DOFManagerDefault; class SparseMatrixAIJ; } namespace akantu { class SparseSolverMumps : public SparseSolver { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseSolverMumps(DOFManagerDefault & dof_manager, const ID & matrix_id, const ID & id = "sparse_solver_mumps", const MemoryID & memory_id = 0); ~SparseSolverMumps() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// build the profile and do the analysis part void initialize() override; /// analysis (symbolic facto + permutations) void analysis() override; /// factorize the matrix void factorize() override; /// solve the system virtual void solve(Array<Real> & x, const Array<Real> & b); /// solve using residual and solution from the dof_manager void solve() override; private: /// print the error if any happened in mumps void printError(); /// solve the system with master_rhs_solution as b and x void solveInternal(); /// set internal values; void initMumpsData(); /// set the level of verbosity of mumps based on the debug level of akantu void setOutputLevel(); protected: /// de-initialize the internal data void destroyInternalData() override; /// check if initialized and except if it is not the case void checkInitialized(); private: void mumpsDataDestroy(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ private: /// access the control variable inline Int & icntl(UInt i) { return mumps_data.icntl[i - 1]; } /// access the results info inline Int & info(UInt i) { return mumps_data.info[i - 1]; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// DOFManager used by the Mumps implementation of the SparseSolver DOFManagerDefault & dof_manager; /// Full right hand side on the master processors and solution after solve Array<Real> master_rhs_solution; /// mumps data DMUMPS_STRUC_C mumps_data; /// Rank of the current process UInt prank; /// matrix release at last solve UInt last_profile_release{UInt(-1)}; /// matrix release at last solve UInt last_value_release{UInt(-1)}; /// check if the solver data are initialized bool is_initialized{false}; /* ------------------------------------------------------------------------ */ /* Local types */ /* ------------------------------------------------------------------------ */ private: SolverParallelMethod parallel_method; // bool rhs_is_local; enum SolverMumpsJob { _smj_initialize = -1, _smj_analyze = 1, _smj_factorize = 2, _smj_solve = 3, _smj_analyze_factorize = 4, _smj_factorize_solve = 5, _smj_complete = 6, // analyze, factorize, solve _smj_destroy = -2 }; }; } // akantu #endif /* __AKANTU_SOLVER_MUMPS_HH__ */ diff --git a/src/solver/terms_to_assemble.hh b/src/solver/terms_to_assemble.hh index 375d30fe4..4b4d834ff 100644 --- a/src/solver/terms_to_assemble.hh +++ b/src/solver/terms_to_assemble.hh @@ -1,99 +1,100 @@ /** * @file terms_to_assemble.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Tue Dec 20 2016 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Nov 08 2017 * - * @brief List of terms to assemble to a matrix + * @brief List of terms to assemble to a matrix * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TERMS_TO_ASSEMBLE_HH__ #define __AKANTU_TERMS_TO_ASSEMBLE_HH__ namespace akantu { class TermsToAssemble { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: TermsToAssemble() = default; virtual ~TermsToAssemble() = default; class TermToAssemble { public: TermToAssemble(UInt i, UInt j) : _i(i), _j(j), val(0.) {} inline TermToAssemble & operator=(Real val) { this->val = val; return *this; } inline TermToAssemble operator+=(Real val) { this->val += val; return *this; } inline operator Real() const { return val; } inline UInt i() const { return _i; } inline UInt j() const { return _j; } private: UInt _i, _j; Real val; }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: inline TermToAssemble & operator()(UInt i, UInt j) { terms.emplace_back(i, j); return terms.back(); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ private: using TermsContainer = std::vector<TermToAssemble>; public: using const_terms_iterator = TermsContainer::const_iterator; const_terms_iterator begin() const { return terms.begin(); } const_terms_iterator end() const { return terms.end(); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: TermsContainer terms; }; } // akantu #endif /* __AKANTU_TERMS_TO_ASSEMBLE_HH__ */ diff --git a/src/synchronizer/communication_buffer.hh b/src/synchronizer/communication_buffer.hh index 5cd056d1e..5e0b0da8d 100644 --- a/src/synchronizer/communication_buffer.hh +++ b/src/synchronizer/communication_buffer.hh @@ -1,183 +1,182 @@ /** * @file communication_buffer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief Buffer for packing and unpacking data * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "element.hh" #ifndef __AKANTU_COMMUNICATION_BUFFER_HH__ #define __AKANTU_COMMUNICATION_BUFFER_HH__ namespace akantu { template <bool is_static = true> class CommunicationBufferTemplated { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit CommunicationBufferTemplated(UInt size) : buffer(size, 1) { ptr_pack = buffer.storage(); ptr_unpack = buffer.storage(); }; CommunicationBufferTemplated() : CommunicationBufferTemplated(0) {} CommunicationBufferTemplated(const CommunicationBufferTemplated & other) { buffer = other.buffer; ptr_pack = buffer.storage(); ptr_unpack = buffer.storage(); } CommunicationBufferTemplated & operator=(const CommunicationBufferTemplated & other) { if (this != &other) { buffer = other.buffer; ptr_pack = buffer.storage(); ptr_unpack = buffer.storage(); } return *this; } virtual ~CommunicationBufferTemplated() = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// reset to "empty" inline void reset(); /// resize the internal buffer inline void resize(UInt size); /// clear buffer context inline void clear(); private: inline void packResize(UInt size); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: inline char * storage() { return buffer.storage(); }; inline const char * storage() const { return buffer.storage(); }; /* ------------------------------------------------------------------------ */ /* Operators */ /* ------------------------------------------------------------------------ */ public: /// printing tool template <typename T> inline std::string extractStream(UInt packet_size); /// packing data template <typename T> inline CommunicationBufferTemplated & operator<<(const T & to_pack); template <typename T> inline CommunicationBufferTemplated & operator<<(const Vector<T> & to_pack); template <typename T> inline CommunicationBufferTemplated & operator<<(const Matrix<T> & to_pack); template <typename T> inline CommunicationBufferTemplated & operator<<(const std::vector<T> & to_pack); /// unpacking data template <typename T> inline CommunicationBufferTemplated & operator>>(T & to_unpack); template <typename T> inline CommunicationBufferTemplated & operator>>(Vector<T> & to_unpack); template <typename T> inline CommunicationBufferTemplated & operator>>(Matrix<T> & to_unpack); template <typename T> inline CommunicationBufferTemplated & operator>>(std::vector<T> & to_unpack); inline CommunicationBufferTemplated & operator<<(const std::string & to_pack); inline CommunicationBufferTemplated & operator>>(std::string & to_unpack); private: template <typename T> inline void packIterable(T & to_pack); template <typename T> inline void unpackIterable(T & to_pack); /* ------------------------------------------------------------------------ */ /* Accessor */ /* ------------------------------------------------------------------------ */ public: template <typename T> static inline UInt sizeInBuffer(const T & data); template <typename T> static inline UInt sizeInBuffer(const Vector<T> & data); template <typename T> static inline UInt sizeInBuffer(const Matrix<T> & data); template <typename T> static inline UInt sizeInBuffer(const std::vector<T> & data); static inline UInt sizeInBuffer(const std::string & data); /// return the size in bytes of the stored values inline UInt getPackedSize() const { return ptr_pack - buffer.storage(); }; /// return the size in bytes of data left to be unpacked inline UInt getLeftToUnpack() const { return buffer.size() - (ptr_unpack - buffer.storage()); }; /// return the global size allocated inline UInt size() const { return buffer.size(); }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// current position for packing char * ptr_pack; /// current position for unpacking char * ptr_unpack; /// storing buffer Array<char> buffer; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_INCLUDE_INLINE_IMPL) #include "communication_buffer_inline_impl.cc" #endif using CommunicationBuffer = CommunicationBufferTemplated<true>; using DynamicCommunicationBuffer = CommunicationBufferTemplated<false>; } // namespace akantu #endif /* __AKANTU_COMMUNICATION_BUFFER_HH__ */ diff --git a/src/synchronizer/communication_buffer_inline_impl.cc b/src/synchronizer/communication_buffer_inline_impl.cc index 9e75736e8..d242a4b42 100644 --- a/src/synchronizer/communication_buffer_inline_impl.cc +++ b/src/synchronizer/communication_buffer_inline_impl.cc @@ -1,319 +1,318 @@ /** * @file communication_buffer_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Apr 14 2011 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Wed Nov 08 2017 * * @brief CommunicationBuffer inline implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline UInt CommunicationBufferTemplated<is_static>::sizeInBuffer(const T &) { return sizeof(T); } template <bool is_static> template <typename T> inline UInt CommunicationBufferTemplated<is_static>::sizeInBuffer(const Vector<T> & data) { UInt size = data.size() * sizeof(T); return size; } template <bool is_static> template <typename T> inline UInt CommunicationBufferTemplated<is_static>::sizeInBuffer(const Matrix<T> & data) { UInt size = data.size() * sizeof(T); return size; } template <bool is_static> template <typename T> inline UInt CommunicationBufferTemplated<is_static>::sizeInBuffer( const std::vector<T> & data) { UInt size = data.size() * sizeof(T) + sizeof(size_t); return size; } template <bool is_static> inline UInt CommunicationBufferTemplated<is_static>::sizeInBuffer( const std::string & data) { UInt size = data.size() * sizeof(std::string::value_type) + sizeof(size_t); return size; } /* -------------------------------------------------------------------------- */ template <bool is_static> inline void CommunicationBufferTemplated<is_static>::packResize(UInt size) { if (!is_static) { char * values = buffer.storage(); buffer.resize(buffer.size() + size); ptr_pack = buffer.storage() + (ptr_pack - values); ptr_unpack = buffer.storage() + (ptr_unpack - values); } } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>::operator<<(const T & to_pack) { UInt size = sizeInBuffer(to_pack); packResize(size); AKANTU_DEBUG_ASSERT( (buffer.storage() + buffer.size()) >= (ptr_pack + size), "Packing too much data in the CommunicationBufferTemplated"); memcpy(ptr_pack, reinterpret_cast<const char *>(&to_pack), size); ptr_pack += size; return *this; } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>::operator>>(T & to_unpack) { UInt size = sizeInBuffer(to_unpack); alignas(alignof(T)) std::array<char, sizeof(T)> aligned_ptr; memcpy(aligned_ptr.data(), ptr_unpack, size); auto * tmp = reinterpret_cast<T *>(aligned_ptr.data()); AKANTU_DEBUG_ASSERT( (buffer.storage() + buffer.size()) >= (ptr_unpack + size), "Unpacking too much data in the CommunicationBufferTemplated"); to_unpack = *tmp; // memcpy(reinterpret_cast<char *>(&to_unpack), ptr_unpack, size); ptr_unpack += size; return *this; } /* -------------------------------------------------------------------------- */ /* Specialization */ /* -------------------------------------------------------------------------- */ /** * Vector */ /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>::operator<<(const Vector<T> & to_pack) { UInt size = sizeInBuffer(to_pack); packResize(size); AKANTU_DEBUG_ASSERT( (buffer.storage() + buffer.size()) >= (ptr_pack + size), "Packing too much data in the CommunicationBufferTemplated"); memcpy(ptr_pack, to_pack.storage(), size); ptr_pack += size; return *this; } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>::operator>>(Vector<T> & to_unpack) { UInt size = sizeInBuffer(to_unpack); AKANTU_DEBUG_ASSERT( (buffer.storage() + buffer.size()) >= (ptr_unpack + size), "Unpacking too much data in the CommunicationBufferTemplated"); memcpy(to_unpack.storage(), ptr_unpack, size); ptr_unpack += size; return *this; } /** * Matrix */ /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>::operator<<(const Matrix<T> & to_pack) { UInt size = sizeInBuffer(to_pack); packResize(size); AKANTU_DEBUG_ASSERT( (buffer.storage() + buffer.size()) >= (ptr_pack + size), "Packing too much data in the CommunicationBufferTemplated"); memcpy(ptr_pack, to_pack.storage(), size); ptr_pack += size; return *this; } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>::operator>>(Matrix<T> & to_unpack) { UInt size = sizeInBuffer(to_unpack); AKANTU_DEBUG_ASSERT( (buffer.storage() + buffer.size()) >= (ptr_unpack + size), "Unpacking too much data in the CommunicationBufferTemplated"); memcpy(to_unpack.storage(), ptr_unpack, size); ptr_unpack += size; return *this; } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline void CommunicationBufferTemplated<is_static>::packIterable(T & to_pack) { operator<<(size_t(to_pack.size())); auto it = to_pack.begin(); auto end = to_pack.end(); for (; it != end; ++it) operator<<(*it); } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline void CommunicationBufferTemplated<is_static>::unpackIterable(T & to_unpack) { size_t size; operator>>(size); to_unpack.resize(size); auto it = to_unpack.begin(); auto end = to_unpack.end(); for (; it != end; ++it) operator>>(*it); } /** * std::vector<T> */ /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>:: operator<<(const std::vector<T> & to_pack) { packIterable(to_pack); return *this; } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>:: operator>>(std::vector<T> & to_unpack) { unpackIterable(to_unpack); return *this; } /** * std::string */ /* -------------------------------------------------------------------------- */ template <bool is_static> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>:: operator<<(const std::string & to_pack) { packIterable(to_pack); return *this; } /* -------------------------------------------------------------------------- */ template <bool is_static> inline CommunicationBufferTemplated<is_static> & CommunicationBufferTemplated<is_static>::operator>>(std::string & to_unpack) { unpackIterable(to_unpack); return *this; } /* -------------------------------------------------------------------------- */ template <bool is_static> template <typename T> inline std::string CommunicationBufferTemplated<is_static>::extractStream(UInt block_size) { std::stringstream str; auto * ptr = reinterpret_cast<T *>(buffer.storage()); UInt sz = buffer.size() / sizeof(T); UInt sz_block = block_size / sizeof(T); UInt n_block = 0; for (UInt i = 0; i < sz; ++i) { if (i % sz_block == 0) { str << std::endl << n_block << " "; ++n_block; } str << *ptr << " "; ++ptr; } return str.str(); } /* -------------------------------------------------------------------------- */ template <bool is_static> inline void CommunicationBufferTemplated<is_static>::resize(UInt size) { if (!is_static) { buffer.resize(0); } else { buffer.resize(size); } reset(); #ifndef AKANTU_NDEBUG clear(); #endif } /* -------------------------------------------------------------------------- */ template <bool is_static> inline void CommunicationBufferTemplated<is_static>::clear() { buffer.clear(); } /* -------------------------------------------------------------------------- */ template <bool is_static> inline void CommunicationBufferTemplated<is_static>::reset() { ptr_pack = buffer.storage(); ptr_unpack = buffer.storage(); } /* -------------------------------------------------------------------------- */ // template<bool is_static> // inline CommunicationBufferTemplated<is_static> & // CommunicationBufferTemplated<is_static>::packMeshData (const MeshData & // to_pack, const ElementType & type) { // UInt size = to_pack.size(); // operator<<(size); // typename std::vector<T>::iterator it = to_pack.begin(); // typename std::vector<T>::iterator end = to_pack.end(); // for(;it != end; ++it) operator<<(*it); // return *this; //} diff --git a/src/synchronizer/communication_descriptor.hh b/src/synchronizer/communication_descriptor.hh index 373abd5b1..246422f47 100644 --- a/src/synchronizer/communication_descriptor.hh +++ b/src/synchronizer/communication_descriptor.hh @@ -1,153 +1,154 @@ /** - * @file synchronizer_tmpl.hh + * @file communication_descriptor.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 3 13:49:36 2016 + * @date creation: Wed Sep 07 2016 + * @date last modification: Thu Jan 25 2018 * * @brief Implementation of the helper classes for the synchronizer * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "communication_request.hh" #include "communication_tag.hh" #include "data_accessor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ #define __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ namespace akantu { /* ------------------------------------------------------------------------ */ enum CommunicationSendRecv { _send, _recv, _csr_not_defined }; /* -------------------------------------------------------------------------- */ struct CommunicationSRType { using type = CommunicationSendRecv; static const type _begin_ = _send; static const type _end_ = _csr_not_defined; }; using send_recv_t = safe_enum<CommunicationSRType>; namespace { send_recv_t iterate_send_recv{}; } /* ------------------------------------------------------------------------ */ class Communication { public: explicit Communication(const CommunicationSendRecv & type = _csr_not_defined) : _type(type) {} Communication(const Communication &) = delete; Communication & operator=(const Communication &) = delete; void resize(UInt size) { this->_size = size; this->_buffer.resize(size); } inline const CommunicationSendRecv & type() const { return this->_type; } inline const UInt & size() const { return this->_size; } inline const CommunicationRequest & request() const { return this->_request; } inline CommunicationRequest & request() { return this->_request; } inline const CommunicationBuffer & buffer() const { return this->_buffer; } inline CommunicationBuffer & buffer() { return this->_buffer; } private: UInt _size{0}; CommunicationBuffer _buffer; CommunicationRequest _request; CommunicationSendRecv _type; }; template <class Entity> class Communications; /* ------------------------------------------------------------------------ */ template <class Entity> class CommunicationDescriptor { public: CommunicationDescriptor(Communication & communication, Array<Entity> & scheme, Communications<Entity> & communications, const SynchronizationTag & tag, UInt proc); CommunicationDescriptor(const CommunicationDescriptor &) = default; CommunicationDescriptor & operator=(const CommunicationDescriptor &) = default; /// get the quantity of data in the buffer UInt getNbData() { return communication.size(); } /// set the quantity of data in the buffer void setNbData(UInt size) { communication.resize(size); } /// get the corresponding tag const SynchronizationTag & getTag() const { return tag; } /// get the data buffer CommunicationBuffer & getBuffer(); /// get the corresponding request CommunicationRequest & getRequest(); /// get the communication scheme const Array<Entity> & getScheme(); /// reset the buffer before pack or after unpack void resetBuffer(); /// pack data for entities in the buffer void packData(const DataAccessor<Entity> & accessor); /// unpack data for entities from the buffer void unpackData(DataAccessor<Entity> & accessor); /// posts asynchronous send requests void postSend(int hash_id); /// posts asynchronous receive requests void postRecv(int hash_id); /// free the request void freeRequest(); UInt getProc() { return proc; } protected: Communication & communication; const Array<Entity> & scheme; Communications<Entity> & communications; const SynchronizationTag & tag; UInt proc; UInt rank; UInt counter; }; /* -------------------------------------------------------------------------- */ } // namespace akantu #include "communication_descriptor_tmpl.hh" #endif /* __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ */ diff --git a/src/synchronizer/communication_descriptor_tmpl.hh b/src/synchronizer/communication_descriptor_tmpl.hh index 8b61411ec..92044ef1a 100644 --- a/src/synchronizer/communication_descriptor_tmpl.hh +++ b/src/synchronizer/communication_descriptor_tmpl.hh @@ -1,151 +1,152 @@ /** * @file communication_descriptor_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Sep 6 14:03:16 2016 + * @date creation: Wed Sep 07 2016 + * @date last modification: Thu Jan 25 2018 * * @brief implementation of CommunicationDescriptor * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communication_descriptor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATION_DESCRIPTOR_TMPL_HH__ #define __AKANTU_COMMUNICATION_DESCRIPTOR_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Implementations */ /* -------------------------------------------------------------------------- */ template <class Entity> CommunicationDescriptor<Entity>::CommunicationDescriptor( Communication & communication, Array<Entity> & scheme, Communications<Entity> & communications, const SynchronizationTag & tag, UInt proc) : communication(communication), scheme(scheme), communications(communications), tag(tag), proc(proc), rank(communications.getCommunicator().whoAmI()) { counter = communications.getCounter(tag); } /* -------------------------------------------------------------------------- */ template <class Entity> CommunicationBuffer & CommunicationDescriptor<Entity>::getBuffer() { return communication.buffer(); } /* -------------------------------------------------------------------------- */ template <class Entity> CommunicationRequest & CommunicationDescriptor<Entity>::getRequest() { return communication.request(); } /* -------------------------------------------------------------------------- */ template <class Entity> void CommunicationDescriptor<Entity>::freeRequest() { const auto & comm = communications.getCommunicator(); // comm.test(communication.request()); comm.freeCommunicationRequest(communication.request()); communications.decrementPending(tag, communication.type()); } /* -------------------------------------------------------------------------- */ template <class Entity> const Array<Entity> & CommunicationDescriptor<Entity>::getScheme() { return scheme; } template <class Entity> void CommunicationDescriptor<Entity>::resetBuffer() { this->communication.buffer().reset(); } /* -------------------------------------------------------------------------- */ template <class Entity> void CommunicationDescriptor<Entity>::packData( const DataAccessor<Entity> & accessor) { AKANTU_DEBUG_ASSERT( communication.type() == _send, "Cannot pack data on communication that is not of type _send"); accessor.packData(communication.buffer(), scheme, tag); } /* -------------------------------------------------------------------------- */ template <class Entity> void CommunicationDescriptor<Entity>::unpackData( DataAccessor<Entity> & accessor) { AKANTU_DEBUG_ASSERT( communication.type() == _recv, "Cannot unpack data from communication that is not of type _recv"); accessor.unpackData(communication.buffer(), scheme, tag); } /* -------------------------------------------------------------------------- */ template <class Entity> void CommunicationDescriptor<Entity>::postSend(int hash_id) { AKANTU_DEBUG_ASSERT(communication.type() == _send, "Cannot send a communication that is not of type _send"); Tag comm_tag = Tag::genTag(rank, counter, tag, hash_id); AKANTU_DEBUG_ASSERT(communication.buffer().getPackedSize() == communication.size(), "a problem have been introduced with " << "false sent sizes declaration " << communication.buffer().getPackedSize() << " != " << communication.size()); AKANTU_DEBUG_INFO("Posting send to proc " << proc << " (tag: " << tag << " - " << communication.size() << " data to send) " << " [ " << comm_tag << " ]"); CommunicationRequest & request = communication.request(); request = communications.getCommunicator().asyncSend(communication.buffer(), proc, comm_tag); communications.incrementPending(tag, communication.type()); } /* -------------------------------------------------------------------------- */ template <class Entity> void CommunicationDescriptor<Entity>::postRecv(int hash_id) { AKANTU_DEBUG_ASSERT(communication.type() == _recv, "Cannot receive data for communication (" << communication.type() << ")that is not of type _recv"); Tag comm_tag = Tag::genTag(proc, counter, tag, hash_id); AKANTU_DEBUG_INFO("Posting receive from proc " << proc << " (tag: " << tag << " - " << communication.size() << " data to receive) " << " [ " << comm_tag << " ]"); CommunicationRequest & request = communication.request(); request = communications.getCommunicator().asyncReceive( communication.buffer(), proc, comm_tag); communications.incrementPending(tag, communication.type()); } } // akantu #endif /* __AKANTU_COMMUNICATION_DESCRIPTOR_TMPL_HH__ */ diff --git a/src/synchronizer/communication_request.hh b/src/synchronizer/communication_request.hh index f93ba330c..73b83e0ec 100644 --- a/src/synchronizer/communication_request.hh +++ b/src/synchronizer/communication_request.hh @@ -1,113 +1,112 @@ /** - * @file real_static_communicator.hh + * @file communication_request.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 - * @date last modification: Wed Jan 13 2016 + * @date last modification: Wed Nov 08 2017 * * @brief empty class just for inheritance * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <memory> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ #define __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ class InternalCommunicationRequest { public: InternalCommunicationRequest(UInt source, UInt dest); virtual ~InternalCommunicationRequest(); virtual void printself(std::ostream & stream, int indent = 0) const; AKANTU_GET_MACRO(Source, source, UInt); AKANTU_GET_MACRO(Destination, destination, UInt); private: UInt source; UInt destination; UInt id; static UInt counter; }; /* -------------------------------------------------------------------------- */ class CommunicationRequest { public: CommunicationRequest( std::shared_ptr<InternalCommunicationRequest> request = nullptr) : request(std::move(request)) {} virtual ~CommunicationRequest() = default; virtual void free() { request.reset(); } void printself(std::ostream & stream, int indent = 0) const { request->printself(stream, indent); }; UInt getSource() const { return request->getSource(); } UInt getDestination() const { return request->getDestination(); } bool isFreed() const { return request.get() == nullptr; } InternalCommunicationRequest & getInternal() { return *request; } private: std::shared_ptr<InternalCommunicationRequest> request; }; /* -------------------------------------------------------------------------- */ class CommunicationStatus { public: AKANTU_GET_MACRO(Source, source, Int); UInt size() const { return size_; } AKANTU_GET_MACRO(Tag, tag, Int); AKANTU_SET_MACRO(Source, source, Int); AKANTU_SET_MACRO(Size, size_, UInt); AKANTU_SET_MACRO(Tag, tag, Int); private: Int source{0}; UInt size_{0}; Int tag{0}; }; /* -------------------------------------------------------------------------- */ /// Datatype to pack pairs for MPI_{MIN,MAX}LOC template <typename T1, typename T2> struct SCMinMaxLoc { T1 min_max; T2 loc; }; } // akantu #endif /* __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ */ diff --git a/src/synchronizer/communication_tag.hh b/src/synchronizer/communication_tag.hh index e6fb54a82..f9c125ea1 100644 --- a/src/synchronizer/communication_tag.hh +++ b/src/synchronizer/communication_tag.hh @@ -1,116 +1,118 @@ /** * @file communication_tag.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 24 12:40:55 2016 + * @date creation: Wed Sep 07 2016 + * @date last modification: Wed Nov 08 2017 * * @brief Description of the communication tags * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + #ifndef __AKANTU_COMMUNICATION_TAG_HH__ #define __AKANTU_COMMUNICATION_TAG_HH__ namespace akantu { /** * tag = |__________20_________|___8____|_4_| * | proc | num mes| ct| */ class Tag { public: Tag() = default; Tag(int val) : tag(val) {} Tag(int val, int hash) : tag(val), hash(hash) {} operator int() const { return int(max_tag == 0 ? tag : (uint32_t(tag) % max_tag)); } /// generates a tag template <typename CommTag> static inline Tag genTag(int proc, UInt msg_count, CommTag tag) { int _tag = ((((proc & 0xFFFFF) << 12) + ((msg_count & 0xFF) << 4) + ((int)tag & 0xF))); Tag t(_tag); return t; } /// generates a tag and hashes it template <typename CommTag> static inline Tag genTag(int proc, UInt msg_count, CommTag tag, int hash) { Tag t = genTag(proc, msg_count, tag); t.tag = t.tag ^ hash; t.hash = hash; return t; } virtual void printself(std::ostream & stream, int) const { int t = tag; stream << "TAG("; if (hash != 0) t = t ^ hash; stream << (t >> 12) << ":" << (t >> 4 & 0xFF) << ":" << (t & 0xF) << " -> " << std::hex << "0x" << int(*this); if (hash != 0) stream << " {hash: 0x" << hash << "}"; stream << " [0x" << this->max_tag << "]"; stream << ")"; } enum CommTags : int { _SIZES = 1, _CONNECTIVITY = 2, _DATA = 3, _PARTITIONS = 4, _NB_NODES = 5, _NODES = 6, _COORDINATES = 7, _NODES_TYPE = 8, _MESH_DATA = 9, _ELEMENT_GROUP = 10, _NODE_GROUP = 11, _MODIFY_SCHEME = 12, _GATHER_INITIALIZATION = 1, _GATHER = 2, _SCATTER = 3, _SYNCHRONIZE = 15, }; private: static void setMaxTag(int _max_tag) { max_tag = _max_tag; } friend void initialize(const std::string &, int &, char **&); private: int tag{0}; int hash{0}; static int max_tag; }; /* -------------------------------------------------------------------------- */ inline std::ostream & operator<<(std::ostream & stream, const Tag & _this) { _this.printself(stream, 0); return stream; } /* -------------------------------------------------------------------------- */ } #endif /* __AKANTU_COMMUNICATION_TAG_HH__ */ diff --git a/src/synchronizer/communications.hh b/src/synchronizer/communications.hh index 8190e94ed..f3968b4e3 100644 --- a/src/synchronizer/communications.hh +++ b/src/synchronizer/communications.hh @@ -1,272 +1,274 @@ /** * @file communications.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 24 13:56:14 2016 + * @date creation: Wed Sep 07 2016 + * @date last modification: Tue Feb 20 2018 * - * @brief + * @brief Class handling the pending communications and the communications + * schemes * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communication_descriptor.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_HH__ #define __AKANTU_COMMUNICATIONS_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class Entity> class Communications { public: using Scheme = Array<Entity>; protected: using CommunicationPerProcs = std::map<UInt, Communication>; using CommunicationsPerTags = std::map<SynchronizationTag, CommunicationPerProcs>; using CommunicationSchemes = std::map<UInt, Scheme>; using Request = std::map<UInt, std::vector<CommunicationRequest>>; friend class CommunicationDescriptor<Entity>; public: using scheme_iterator = typename CommunicationSchemes::iterator; using const_scheme_iterator = typename CommunicationSchemes::const_iterator; /* ------------------------------------------------------------------------ */ class iterator; class tag_iterator; /* ------------------------------------------------------------------------ */ public: CommunicationPerProcs & getCommunications(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ bool hasPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; UInt getPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ iterator begin(const SynchronizationTag & tag, const CommunicationSendRecv & sr); iterator end(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ iterator waitAny(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void waitAll(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void incrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void decrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void freeRequests(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ Scheme & createScheme(UInt proc, const CommunicationSendRecv & sr); void resetSchemes(const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void setCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size, const CommunicationSendRecv & sr); public: explicit Communications(const Communicator & communicator); explicit Communications(const Communications & communications); /* ------------------------------------------------------------------------ */ class IterableCommunicationDesc { public: IterableCommunicationDesc(Communications & communications, SynchronizationTag tag, CommunicationSendRecv sr) : communications(communications), tag(std::move(tag)), sr(std::move(sr)) {} auto begin() { return communications.begin(tag, sr); } auto end() { return communications.end(tag, sr); } private: Communications & communications; SynchronizationTag tag; CommunicationSendRecv sr; }; auto iterateRecv(const SynchronizationTag & tag) { return IterableCommunicationDesc(*this, tag, _recv); } auto iterateSend(const SynchronizationTag & tag) { return IterableCommunicationDesc(*this, tag, _send); } /* ------------------------------------------------------------------------ */ // iterator begin_send(const SynchronizationTag & tag); // iterator end_send(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ // iterator begin_recv(const SynchronizationTag & tag); // iterator end_recv(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ class IterableTags { public: explicit IterableTags(Communications & communications) : communications(communications) {} decltype(auto) begin() { return communications.begin_tag(); } decltype(auto) end() { return communications.end_tag(); } private: Communications & communications; }; decltype(auto) iterateTags() { return IterableTags(*this); } tag_iterator begin_tag(); tag_iterator end_tag(); /* ------------------------------------------------------------------------ */ bool hasCommunication(const SynchronizationTag & tag) const; void incrementCounter(const SynchronizationTag & tag); UInt getCounter(const SynchronizationTag & tag) const; bool hasCommunicationSize(const SynchronizationTag & tag) const; void invalidateSizes(); /* ------------------------------------------------------------------------ */ bool hasPendingRecv(const SynchronizationTag & tag) const; bool hasPendingSend(const SynchronizationTag & tag) const; const auto & getCommunicator() const; /* ------------------------------------------------------------------------ */ iterator waitAnyRecv(const SynchronizationTag & tag); iterator waitAnySend(const SynchronizationTag & tag); void waitAllRecv(const SynchronizationTag & tag); void waitAllSend(const SynchronizationTag & tag); void freeSendRequests(const SynchronizationTag & tag); void freeRecvRequests(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ class IterableSchemes { public: IterableSchemes(Communications & communications, CommunicationSendRecv sr) : communications(communications), sr(std::move(sr)) {} decltype(auto) begin() { return communications.begin_scheme(sr); } decltype(auto) end() { return communications.end_scheme(sr); } private: Communications & communications; CommunicationSendRecv sr; }; class ConstIterableSchemes { public: ConstIterableSchemes(const Communications & communications, CommunicationSendRecv sr) : communications(communications), sr(std::move(sr)) {} decltype(auto) begin() const { return communications.begin_scheme(sr); } decltype(auto) end() const { return communications.end_scheme(sr); } private: const Communications & communications; CommunicationSendRecv sr; }; decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) { return IterableSchemes(*this, sr); } decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) const { return ConstIterableSchemes(*this, sr); } decltype(auto) iterateSendSchemes() { return IterableSchemes(*this, _send); } decltype(auto) iterateSendSchemes() const { return ConstIterableSchemes(*this, _send); } decltype(auto) iterateRecvSchemes() { return IterableSchemes(*this, _recv); } decltype(auto) iterateRecvSchemes() const { return ConstIterableSchemes(*this, _recv); } scheme_iterator begin_scheme(const CommunicationSendRecv & sr); scheme_iterator end_scheme(const CommunicationSendRecv & sr); const_scheme_iterator begin_scheme(const CommunicationSendRecv & sr) const; const_scheme_iterator end_scheme(const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_send_scheme(); scheme_iterator end_send_scheme(); const_scheme_iterator begin_send_scheme() const; const_scheme_iterator end_send_scheme() const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_recv_scheme(); scheme_iterator end_recv_scheme(); const_scheme_iterator begin_recv_scheme() const; const_scheme_iterator end_recv_scheme() const; /* ------------------------------------------------------------------------ */ Scheme & createSendScheme(UInt proc); Scheme & createRecvScheme(UInt proc); /* ------------------------------------------------------------------------ */ Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr); const Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ void resetSchemes(); /* ------------------------------------------------------------------------ */ void setSendCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void setRecvCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void initializeCommunications(const SynchronizationTag & tag); protected: CommunicationSchemes schemes[2]; CommunicationsPerTags communications[2]; std::map<SynchronizationTag, UInt> comm_counter; std::map<SynchronizationTag, UInt> pending_communications[2]; std::map<SynchronizationTag, bool> comm_size_computed; const Communicator & communicator; }; } // namespace akantu #include "communications_tmpl.hh" #endif /* __AKANTU_COMMUNICATIONS_HH__ */ diff --git a/src/synchronizer/communications_tmpl.hh b/src/synchronizer/communications_tmpl.hh index 9b4f2aef9..71cb69298 100644 --- a/src/synchronizer/communications_tmpl.hh +++ b/src/synchronizer/communications_tmpl.hh @@ -1,550 +1,551 @@ /** * @file communications_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Tue Sep 6 17:14:06 2016 + * @date creation: Wed Sep 07 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of Communications * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communications.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_TMPL_HH__ #define __AKANTU_COMMUNICATIONS_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class Entity> Communications<Entity>::Communications(const Communicator & communicator) : communicator(communicator) {} /* -------------------------------------------------------------------------- */ template <class Entity> Communications<Entity>::Communications(const Communications & other) : communicator(other.communicator) { for (auto sr : iterate_send_recv) { for (const auto & scheme_pair : other.iterateSchemes(sr)) { auto proc = scheme_pair.first; auto & other_scheme = scheme_pair.second; auto & scheme = this->createScheme(proc, sr); scheme.copy(other_scheme); } } this->invalidateSizes(); } /* -------------------------------------------------------------------------- */ template <class Entity> class Communications<Entity>::iterator { using communication_iterator = typename std::map<UInt, Communication>::iterator; public: iterator() : communications(nullptr) {} iterator(scheme_iterator scheme_it, communication_iterator comm_it, Communications<Entity> & communications, const SynchronizationTag & tag) : scheme_it(scheme_it), comm_it(comm_it), communications(&communications), tag(tag) {} iterator & operator=(const iterator & other) { if (this != &other) { this->scheme_it = other.scheme_it; this->comm_it = other.comm_it; this->communications = other.communications; this->tag = other.tag; } return *this; } iterator & operator++() { ++scheme_it; ++comm_it; return *this; } CommunicationDescriptor<Entity> operator*() { AKANTU_DEBUG_ASSERT( scheme_it->first == comm_it->first, "The two iterators are not in phase, something wrong" << " happened, time to take out your favorite debugger (" << scheme_it->first << " != " << comm_it->first << ")"); return CommunicationDescriptor<Entity>(comm_it->second, scheme_it->second, *communications, tag, scheme_it->first); } bool operator==(const iterator & other) const { return scheme_it == other.scheme_it && comm_it == other.comm_it; } bool operator!=(const iterator & other) const { return scheme_it != other.scheme_it || comm_it != other.comm_it; } private: scheme_iterator scheme_it; communication_iterator comm_it; Communications<Entity> * communications; SynchronizationTag tag; }; /* -------------------------------------------------------------------------- */ template <class Entity> class Communications<Entity>::tag_iterator { using internal_iterator = std::map<SynchronizationTag, UInt>::const_iterator; public: tag_iterator(const internal_iterator & it) : it(it) {} tag_iterator & operator++() { ++it; return *this; } SynchronizationTag operator*() { return it->first; } bool operator==(const tag_iterator & other) const { return it == other.it; } bool operator!=(const tag_iterator & other) const { return it != other.it; } private: internal_iterator it; }; /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::CommunicationPerProcs & Communications<Entity>::getCommunications(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto comm_it = this->communications[sr].find(tag); if (comm_it == this->communications[sr].end()) AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No known communications for the tag: " << tag); return comm_it->second; } /* ---------------------------------------------------------------------- */ template <class Entity> UInt Communications<Entity>::getPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) const { const std::map<SynchronizationTag, UInt> & pending = pending_communications[sr]; auto it = pending.find(tag); if (it == pending.end()) return 0; return it->second; } /* -------------------------------------------------------------------------- */ template <class Entity> bool Communications<Entity>::hasPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) const { return this->hasCommunication(tag) && (this->getPending(tag, sr) != 0); } /* ---------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::begin(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); return iterator(this->schemes[sr].begin(), comms.begin(), *this, tag); } template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::end(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); return iterator(this->schemes[sr].end(), comms.end(), *this, tag); } /* ---------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::waitAny(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); auto it = comms.begin(); auto end = comms.end(); std::vector<CommunicationRequest> requests; for (; it != end; ++it) { auto & request = it->second.request(); if (!request.isFreed()) requests.push_back(request); } UInt req_id = communicator.waitAny(requests); if (req_id != UInt(-1)) { auto & request = requests[req_id]; UInt proc = sr == _recv ? request.getSource() : request.getDestination(); return iterator(this->schemes[sr].find(proc), comms.find(proc), *this, tag); } else { return this->end(tag, sr); } } /* ---------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::waitAll(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); auto it = comms.begin(); auto end = comms.end(); std::vector<CommunicationRequest> requests; for (; it != end; ++it) { requests.push_back(it->second.request()); } communicator.waitAll(requests); } template <class Entity> void Communications<Entity>::incrementPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) { ++(pending_communications[sr][tag]); } template <class Entity> void Communications<Entity>::decrementPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) { --(pending_communications[sr][tag]); } template <class Entity> void Communications<Entity>::freeRequests(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { iterator it = this->begin(tag, sr); iterator end = this->end(tag, sr); for (; it != end; ++it) { (*it).freeRequest(); } } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::createScheme(UInt proc, const CommunicationSendRecv & sr) { // scheme_iterator it = schemes[sr].find(proc); // if (it != schemes[sr].end()) { // AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), // "Communication scheme(" // << sr // << ") already created for proc: " << // proc); // } return schemes[sr][proc]; } template <class Entity> void Communications<Entity>::resetSchemes(const CommunicationSendRecv & sr) { auto it = this->schemes[sr].begin(); auto end = this->schemes[sr].end(); for (; it != end; ++it) { it->second.resize(0); } } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::setCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size, const CommunicationSendRecv & sr) { // accessor that fails if it does not exists comm_size_computed[tag] = true; // TODO: need perhaps to be split based on sr auto & comms = this->communications[sr]; auto & comms_per_tag = comms.at(tag); comms_per_tag.at(proc).resize(size); } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::initializeCommunications( const SynchronizationTag & tag) { for (auto t = send_recv_t::begin(); t != send_recv_t::end(); ++t) { pending_communications[*t].insert(std::make_pair(tag, 0)); auto & comms = this->communications[*t]; auto & comms_per_tag = comms.insert(std::make_pair(tag, CommunicationPerProcs())) .first->second; for (auto pair : this->schemes[*t]) { comms_per_tag.emplace(std::piecewise_construct, std::forward_as_tuple(pair.first), std::forward_as_tuple(*t)); } } comm_counter.insert(std::make_pair(tag, 0)); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::tag_iterator Communications<Entity>::begin_tag() { return tag_iterator(comm_counter.begin()); } template <class Entity> typename Communications<Entity>::tag_iterator Communications<Entity>::end_tag() { return tag_iterator(comm_counter.end()); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::begin_scheme(const CommunicationSendRecv & sr) { return this->schemes[sr].begin(); } template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::end_scheme(const CommunicationSendRecv & sr) { return this->schemes[sr].end(); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::begin_scheme(const CommunicationSendRecv & sr) const { return this->schemes[sr].begin(); } template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::end_scheme(const CommunicationSendRecv & sr) const { return this->schemes[sr].end(); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::begin_send_scheme() { return this->begin_scheme(_send); } template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::end_send_scheme() { return this->end_scheme(_send); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::begin_send_scheme() const { return this->begin_scheme(_send); } template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::end_send_scheme() const { return this->end_scheme(_send); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::begin_recv_scheme() { return this->begin_scheme(_recv); } template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::end_recv_scheme() { return this->end_scheme(_recv); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::begin_recv_scheme() const { return this->begin_scheme(_recv); } template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::end_recv_scheme() const { return this->end_scheme(_recv); } /* ------------------------------------------------------------------------ */ template <class Entity> bool Communications<Entity>::hasCommunication( const SynchronizationTag & tag) const { return (communications[_send].find(tag) != communications[_send].end()); } template <class Entity> void Communications<Entity>::incrementCounter(const SynchronizationTag & tag) { auto it = comm_counter.find(tag); if (it == comm_counter.end()) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No counter initialized in communications for the tags: " << tag); } ++(it->second); } template <class Entity> UInt Communications<Entity>::getCounter(const SynchronizationTag & tag) const { auto it = comm_counter.find(tag); if (it == comm_counter.end()) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No counter initialized in communications for the tags: " << tag); } return it->second; } template <class Entity> bool Communications<Entity>::hasCommunicationSize( const SynchronizationTag & tag) const { auto it = comm_size_computed.find(tag); if (it == comm_size_computed.end()) { return false; } return it->second; } template <class Entity> void Communications<Entity>::invalidateSizes() { for (auto && pair : comm_size_computed) { pair.second = true; } } template <class Entity> bool Communications<Entity>::hasPendingRecv( const SynchronizationTag & tag) const { return this->hasPending(tag, _recv); } template <class Entity> bool Communications<Entity>::hasPendingSend( const SynchronizationTag & tag) const { return this->hasPending(tag, _send); } template <class Entity> const auto & Communications<Entity>::getCommunicator() const { return communicator; } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::waitAnyRecv(const SynchronizationTag & tag) { return this->waitAny(tag, _recv); } template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::waitAnySend(const SynchronizationTag & tag) { return this->waitAny(tag, _send); } template <class Entity> void Communications<Entity>::waitAllRecv(const SynchronizationTag & tag) { this->waitAll(tag, _recv); } template <class Entity> void Communications<Entity>::waitAllSend(const SynchronizationTag & tag) { this->waitAll(tag, _send); } template <class Entity> void Communications<Entity>::freeSendRequests(const SynchronizationTag & tag) { this->freeRequests(tag, _send); } template <class Entity> void Communications<Entity>::freeRecvRequests(const SynchronizationTag & tag) { this->freeRequests(tag, _recv); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::createSendScheme(UInt proc) { return createScheme(proc, _send); } template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::createRecvScheme(UInt proc) { return createScheme(proc, _recv); } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::resetSchemes() { resetSchemes(_send); resetSchemes(_recv); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::getScheme(UInt proc, const CommunicationSendRecv & sr) { return this->schemes[sr].find(proc)->second; } /* -------------------------------------------------------------------------- */ template <class Entity> const typename Communications<Entity>::Scheme & Communications<Entity>::getScheme(UInt proc, const CommunicationSendRecv & sr) const { return this->schemes[sr].find(proc)->second; } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::setSendCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size) { this->setCommunicationSize(tag, proc, size, _send); } template <class Entity> void Communications<Entity>::setRecvCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size) { this->setCommunicationSize(tag, proc, size, _recv); } } // namespace akantu #endif /* __AKANTU_COMMUNICATIONS_TMPL_HH__ */ diff --git a/src/synchronizer/communicator.cc b/src/synchronizer/communicator.cc index ff8ae1f9a..fc925697c 100644 --- a/src/synchronizer/communicator.cc +++ b/src/synchronizer/communicator.cc @@ -1,182 +1,181 @@ /** - * @file static_communicator.cc + * @file communicator.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Mon Feb 05 2018 * * @brief implementation of the common part of the static communicator * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communicator.hh" #if defined(AKANTU_USE_MPI) #include "mpi_communicator_data.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { #if defined(AKANTU_USE_MPI) int MPICommunicatorData::is_externaly_initialized = 0; #endif UInt InternalCommunicationRequest::counter = 0; /* -------------------------------------------------------------------------- */ InternalCommunicationRequest::InternalCommunicationRequest(UInt source, UInt dest) : source(source), destination(dest) { this->id = counter++; } /* -------------------------------------------------------------------------- */ InternalCommunicationRequest::~InternalCommunicationRequest() = default; /* -------------------------------------------------------------------------- */ void InternalCommunicationRequest::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "CommunicationRequest [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + source : " << source << std::endl; stream << space << " + destination : " << destination << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ Communicator::~Communicator() { auto * event = new FinalizeCommunicatorEvent(*this); this->sendEvent(*event); delete event; } /* -------------------------------------------------------------------------- */ Communicator & Communicator::getStaticCommunicator() { AKANTU_DEBUG_IN(); if (!static_communicator) { int nb_args = 0; char ** null = nullptr; static_communicator = std::make_unique<Communicator>(nb_args, null, private_member{}); } AKANTU_DEBUG_OUT(); return *static_communicator; } /* -------------------------------------------------------------------------- */ Communicator & Communicator::getStaticCommunicator(int & argc, char **& argv) { if (!static_communicator) static_communicator = std::make_unique<Communicator>(argc, argv, private_member{}); return getStaticCommunicator(); } } // namespace akantu #ifdef AKANTU_USE_MPI #include "communicator_mpi_inline_impl.cc" #else #include "communicator_dummy_inline_impl.cc" #endif namespace akantu { /* -------------------------------------------------------------------------- */ /* Template instantiation */ /* -------------------------------------------------------------------------- */ #define AKANTU_COMM_INSTANTIATE(T) \ template void Communicator::probe<T>(Int sender, Int tag, \ CommunicationStatus & status) const; \ template bool Communicator::asyncProbe<T>( \ Int sender, Int tag, CommunicationStatus & status) const; \ template void Communicator::sendImpl<T>( \ const T * buffer, Int size, Int receiver, Int tag, \ const CommunicationMode & mode) const; \ template void Communicator::receiveImpl<T>(T * buffer, Int size, Int sender, \ Int tag) const; \ template CommunicationRequest Communicator::asyncSendImpl<T>( \ const T * buffer, Int size, Int receiver, Int tag, \ const CommunicationMode & mode) const; \ template CommunicationRequest Communicator::asyncReceiveImpl<T>( \ T * buffer, Int size, Int sender, Int tag) const; \ template void Communicator::allGatherImpl<T>(T * values, int nb_values) \ const; \ template void Communicator::allGatherVImpl<T>(T * values, int * nb_values) \ const; \ template void Communicator::gatherImpl<T>(T * values, int nb_values, \ int root) const; \ template void Communicator::gatherImpl<T>( \ T * values, int nb_values, T * gathered, int nb_gathered) const; \ template void Communicator::gatherVImpl<T>(T * values, int * nb_values, \ int root) const; \ template void Communicator::broadcastImpl<T>(T * values, int nb_values, \ int root) const; \ template void Communicator::allReduceImpl<T>( \ T * values, int nb_values, const SynchronizerOperation & op) const #define MIN_MAX_REAL SCMinMaxLoc<Real, int> AKANTU_COMM_INSTANTIATE(bool); AKANTU_COMM_INSTANTIATE(Real); AKANTU_COMM_INSTANTIATE(UInt); AKANTU_COMM_INSTANTIATE(Int); AKANTU_COMM_INSTANTIATE(char); AKANTU_COMM_INSTANTIATE(NodeType); AKANTU_COMM_INSTANTIATE(MIN_MAX_REAL); #if AKANTU_INTEGER_SIZE > 4 AKANTU_COMM_INSTANTIATE(int); #endif // template void Communicator::send<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * buffer, Int size, Int receiver, Int tag); // template void Communicator::receive<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * buffer, Int size, Int sender, Int tag); // template CommunicationRequest // Communicator::asyncSend<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * buffer, Int size, Int receiver, Int tag); // template CommunicationRequest // Communicator::asyncReceive<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * buffer, Int size, Int sender, Int tag); // template void Communicator::probe<SCMinMaxLoc<Real, int>>( // Int sender, Int tag, CommunicationStatus & status); // template void Communicator::allGather<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * values, int nb_values); // template void Communicator::allGatherV<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * values, int * nb_values); // template void Communicator::gather<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * values, int nb_values, int root); // template void Communicator::gatherV<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * values, int * nb_values, int root); // template void Communicator::broadcast<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * values, int nb_values, int root); // template void Communicator::allReduce<SCMinMaxLoc<Real, int>>( // SCMinMaxLoc<Real, int> * values, int nb_values, // const SynchronizerOperation & op); } // akantu diff --git a/src/synchronizer/communicator.hh b/src/synchronizer/communicator.hh index 045542321..d045722d3 100644 --- a/src/synchronizer/communicator.hh +++ b/src/synchronizer/communicator.hh @@ -1,437 +1,437 @@ /** - * @file static_communicator.hh + * @file communicator.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jan 19 2016 + * @date last modification: Wed Nov 15 2017 * * @brief Class handling the parallel communications * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_event_handler_manager.hh" #include "communication_buffer.hh" #include "communication_request.hh" #include "communicator_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STATIC_COMMUNICATOR_HH__ #define __AKANTU_STATIC_COMMUNICATOR_HH__ namespace akantu { namespace debug { class CommunicationException : public Exception { public: CommunicationException() : Exception("An exception happen during a communication process.") {} }; } // namespace debug /// @enum SynchronizerOperation reduce operation that the synchronizer can /// perform enum class SynchronizerOperation { _sum, _min, _max, _prod, _land, _band, _lor, _bor, _lxor, _bxor, _min_loc, _max_loc, _null }; enum class CommunicationMode { _auto, _synchronous, _ready }; namespace { int _any_source = -1; } } // namespace akantu namespace akantu { struct CommunicatorInternalData { virtual ~CommunicatorInternalData() = default; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ class Communicator : public EventHandlerManager<CommunicatorEventHandler> { struct private_member {}; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Communicator(int & argc, char **& argv, const private_member &); ~Communicator() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Point to Point */ /* ------------------------------------------------------------------------ */ template <typename T> inline void receive(Array<T> & values, Int sender, Int tag) const { return this->receiveImpl( values.storage(), values.size() * values.getNbComponent(), sender, tag); } template <typename Tensor> inline void receive(Tensor & values, Int sender, Int tag, std::enable_if_t<is_tensor<Tensor>::value> * = nullptr) const { return this->receiveImpl(values.storage(), values.size(), sender, tag); } template <bool is_static> inline void receive(CommunicationBufferTemplated<is_static> & values, Int sender, Int tag) const { return this->receiveImpl(values.storage(), values.size(), sender, tag); } template <typename T> inline void receive(T & values, Int sender, Int tag, std::enable_if_t<std::is_arithmetic<T>::value> * = nullptr) const { return this->receiveImpl(&values, 1, sender, tag); } /* ------------------------------------------------------------------------ */ template <typename T> inline void send(const Array<T> & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto) const { return this->sendImpl(values.storage(), values.size() * values.getNbComponent(), receiver, tag, mode); } template <typename Tensor> inline void send(const Tensor & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto, std::enable_if_t<is_tensor<Tensor>::value> * = nullptr) const { return this->sendImpl(values.storage(), values.size(), receiver, tag, mode); } template <bool is_static> inline void send(const CommunicationBufferTemplated<is_static> & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto) const { return this->sendImpl(values.storage(), values.size(), receiver, tag, mode); } template <typename T> inline void send(const T & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto, std::enable_if_t<std::is_arithmetic<T>::value> * = nullptr) const { return this->sendImpl(&values, 1, receiver, tag, mode); } /* ------------------------------------------------------------------------ */ template <typename T> inline CommunicationRequest asyncSend(const Array<T> & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto) const { return this->asyncSendImpl(values.storage(), values.size() * values.getNbComponent(), receiver, tag, mode); } template <typename T> inline CommunicationRequest asyncSend(const std::vector<T> & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto) const { return this->asyncSendImpl(values.data(), values.size(), receiver, tag, mode); } template <typename Tensor> inline CommunicationRequest asyncSend(const Tensor & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto, std::enable_if_t<is_tensor<Tensor>::value> * = nullptr) const { return this->asyncSendImpl(values.storage(), values.size(), receiver, tag, mode); } template <bool is_static> inline CommunicationRequest asyncSend(const CommunicationBufferTemplated<is_static> & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto) const { return this->asyncSendImpl(values.storage(), values.size(), receiver, tag, mode); } template <typename T> inline CommunicationRequest asyncSend(const T & values, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto, std::enable_if_t<std::is_arithmetic<T>::value> * = nullptr) const { return this->asyncSendImpl(&values, 1, receiver, tag, mode); } /* ------------------------------------------------------------------------ */ template <typename T> inline CommunicationRequest asyncReceive(Array<T> & values, Int sender, Int tag) const { return this->asyncReceiveImpl( values.storage(), values.size() * values.getNbComponent(), sender, tag); } template <typename T> inline CommunicationRequest asyncReceive(std::vector<T> & values, Int sender, Int tag) const { return this->asyncReceiveImpl(values.data(), values.size(), sender, tag); } template <typename Tensor, typename = std::enable_if_t<is_tensor<Tensor>::value>> inline CommunicationRequest asyncReceive(Tensor & values, Int sender, Int tag) const { return this->asyncReceiveImpl(values.storage(), values.size(), sender, tag); } template <bool is_static> inline CommunicationRequest asyncReceive(CommunicationBufferTemplated<is_static> & values, Int sender, Int tag) const { return this->asyncReceiveImpl(values.storage(), values.size(), sender, tag); } /* ------------------------------------------------------------------------ */ template <typename T> void probe(Int sender, Int tag, CommunicationStatus & status) const; template <typename T> bool asyncProbe(Int sender, Int tag, CommunicationStatus & status) const; /* ------------------------------------------------------------------------ */ /* Collectives */ /* ------------------------------------------------------------------------ */ template <typename T> inline void allReduce(Array<T> & values, const SynchronizerOperation & op) const { this->allReduceImpl(values.storage(), values.size() * values.getNbComponent(), op); } template <typename Tensor> inline void allReduce(Tensor & values, const SynchronizerOperation & op, std::enable_if_t<is_tensor<Tensor>::value> * = nullptr) const { this->allReduceImpl(values.storage(), values.size(), op); } template <typename T> inline void allReduce(T & values, const SynchronizerOperation & op, std::enable_if_t<std::is_arithmetic<T>::value> * = nullptr) const { this->allReduceImpl(&values, 1, op); } /* ------------------------------------------------------------------------ */ template <typename T> inline void allGather(Array<T> & values) const { AKANTU_DEBUG_ASSERT(UInt(psize) == values.size(), "The array size is not correct"); this->allGatherImpl(values.storage(), values.getNbComponent()); } template <typename Tensor, typename = std::enable_if_t<is_tensor<Tensor>::value>> inline void allGather(Tensor & values) const { AKANTU_DEBUG_ASSERT(UInt(psize) == values.size(), "The vector size is not correct"); this->allGatherImpl(values.storage(), 1); } /* ------------------------------------------------------------------------ */ template <typename T> inline void allGatherV(Array<T> & values, const Array<Int> & sizes) const { this->allGatherVImpl(values.storage(), sizes.storage()); } /* ------------------------------------------------------------------------ */ template <typename T> inline void reduce(Array<T> & values, const SynchronizerOperation & op, int root = 0) const { this->reduceImpl(values.storage(), values.size() * values.getNbComponent(), op, root); } /* ------------------------------------------------------------------------ */ template <typename Tensor> inline void gather(Tensor & values, int root = 0, std::enable_if_t<is_tensor<Tensor>::value> * = nullptr) const { this->gatherImpl(values.storage(), values.getNbComponent(), root); } template <typename T> inline void gather(T values, int root = 0, std::enable_if_t<std::is_arithmetic<T>::value> * = nullptr) const { this->gatherImpl(&values, 1, root); } /* ------------------------------------------------------------------------ */ template <typename Tensor, typename T> inline void gather(Tensor & values, Array<T> & gathered, std::enable_if_t<is_tensor<Tensor>::value> * = nullptr) const { AKANTU_DEBUG_ASSERT(values.size() == gathered.getNbComponent(), "The array size is not correct"); gathered.resize(psize); this->gatherImpl(values.data(), values.size(), gathered.storage(), gathered.getNbComponent()); } template <typename T> inline void gather(T values, Array<T> & gathered, std::enable_if_t<std::is_arithmetic<T>::value> * = nullptr) const { this->gatherImpl(&values, 1, gathered.storage(), 1); } /* ------------------------------------------------------------------------ */ template <typename T> inline void gatherV(Array<T> & values, const Array<Int> & sizes, int root = 0) const { this->gatherVImpl(values.storage(), sizes.storage(), root); } /* ------------------------------------------------------------------------ */ template <typename T> inline void broadcast(Array<T> & values, int root = 0) const { this->broadcastImpl(values.storage(), values.size() * values.getNbComponent(), root); } template <bool is_static> inline void broadcast(CommunicationBufferTemplated<is_static> & values, int root = 0) const { this->broadcastImpl(values.storage(), values.size(), root); } template <typename T> inline void broadcast(T & values, int root = 0) const { this->broadcastImpl(&values, 1, root); } /* ------------------------------------------------------------------------ */ void barrier() const; CommunicationRequest asyncBarrier() const; /* ------------------------------------------------------------------------ */ /* Request handling */ /* ------------------------------------------------------------------------ */ bool test(CommunicationRequest & request) const; bool testAll(std::vector<CommunicationRequest> & request) const; void wait(CommunicationRequest & request) const; void waitAll(std::vector<CommunicationRequest> & requests) const; UInt waitAny(std::vector<CommunicationRequest> & requests) const; inline void freeCommunicationRequest(CommunicationRequest & request) const; inline void freeCommunicationRequest(std::vector<CommunicationRequest> & requests) const; template <typename T, typename MsgProcessor, typename TagGen> inline void receiveAnyNumber(std::vector<CommunicationRequest> & send_requests, Array<T> receive_buffer, MsgProcessor && processor, TagGen && tag_gen) const; protected: template <typename T> void sendImpl(const T * buffer, Int size, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto) const; template <typename T> void receiveImpl(T * buffer, Int size, Int sender, Int tag) const; template <typename T> CommunicationRequest asyncSendImpl( const T * buffer, Int size, Int receiver, Int tag, const CommunicationMode & mode = CommunicationMode::_auto) const; template <typename T> CommunicationRequest asyncReceiveImpl(T * buffer, Int size, Int sender, Int tag) const; template <typename T> void allReduceImpl(T * values, int nb_values, const SynchronizerOperation & op) const; template <typename T> void allGatherImpl(T * values, int nb_values) const; template <typename T> void allGatherVImpl(T * values, int * nb_values) const; template <typename T> void reduceImpl(T * values, int nb_values, const SynchronizerOperation & op, int root = 0) const; template <typename T> void gatherImpl(T * values, int nb_values, int root = 0) const; template <typename T> void gatherImpl(T * values, int nb_values, T * gathered, int nb_gathered = 0) const; template <typename T> void gatherVImpl(T * values, int * nb_values, int root = 0) const; template <typename T> void broadcastImpl(T * values, int nb_values, int root = 0) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: Int getNbProc() const { return psize; }; Int whoAmI() const { return prank; }; static Communicator & getStaticCommunicator(); static Communicator & getStaticCommunicator(int & argc, char **& argv); int getMaxTag() const; int getMinTag() const; AKANTU_GET_MACRO(CommunicatorData, (*communicator_data), decltype(auto)); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: static std::unique_ptr<Communicator> static_communicator; protected: Int prank{0}; Int psize{1}; std::unique_ptr<CommunicatorInternalData> communicator_data; }; inline std::ostream & operator<<(std::ostream & stream, const CommunicationRequest & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "communicator_inline_impl.hh" #endif /* __AKANTU_STATIC_COMMUNICATOR_HH__ */ diff --git a/src/synchronizer/communicator_dummy_inline_impl.cc b/src/synchronizer/communicator_dummy_inline_impl.cc index 9b92a14fd..79aead7f4 100644 --- a/src/synchronizer/communicator_dummy_inline_impl.cc +++ b/src/synchronizer/communicator_dummy_inline_impl.cc @@ -1,118 +1,117 @@ /** - * @file static_communicator_dummy.hh + * @file communicator_dummy_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Fri Jun 18 2010 - * @date last modification: Wed Jan 13 2016 + * @date creation: Tue Nov 07 2017 + * @date last modification: Fri Nov 10 2017 * * @brief Dummy communicator to make everything work im sequential * * @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) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <cstring> #include <type_traits> #include <vector> /* -------------------------------------------------------------------------- */ namespace akantu { Communicator::Communicator(int & /*argc*/, char **& /*argv*/, const private_member & /*unused*/) {} template <typename T> void Communicator::sendImpl(const T *, Int, Int, Int, const CommunicationMode &) const {} template <typename T> void Communicator::receiveImpl(T *, Int, Int, Int) const {} template <typename T> CommunicationRequest Communicator::asyncSendImpl(const T *, Int, Int, Int, const CommunicationMode &) const { return std::shared_ptr<InternalCommunicationRequest>( new InternalCommunicationRequest(0, 0)); } template <typename T> CommunicationRequest Communicator::asyncReceiveImpl(T *, Int, Int, Int) const { return std::shared_ptr<InternalCommunicationRequest>( new InternalCommunicationRequest(0, 0)); } template <typename T> void Communicator::probe(Int, Int, CommunicationStatus &) const {} template <typename T> bool Communicator::asyncProbe(Int, Int, CommunicationStatus &) const { return true; } bool Communicator::test(CommunicationRequest &) const { return true; } bool Communicator::testAll(std::vector<CommunicationRequest> &) const { return true; } void Communicator::wait(CommunicationRequest &) const {} void Communicator::waitAll(std::vector<CommunicationRequest> &) const {} UInt Communicator::waitAny(std::vector<CommunicationRequest> &) const { return UInt(-1); } void Communicator::barrier() const {} CommunicationRequest Communicator::asyncBarrier() const { return std::shared_ptr<InternalCommunicationRequest>( new InternalCommunicationRequest(0, 0)); } template <typename T> void Communicator::reduceImpl(T *, int, const SynchronizerOperation &, int) const {} template <typename T> void Communicator::allReduceImpl(T *, int, const SynchronizerOperation &) const {} template <typename T> inline void Communicator::allGatherImpl(T *, int) const {} template <typename T> inline void Communicator::allGatherVImpl(T *, int *) const {} template <typename T> inline void Communicator::gatherImpl(T *, int, int) const {} template <typename T> void Communicator::gatherImpl(T * values, int nb_values, T * gathered, int) const { static_assert(std::is_trivially_copyable<T>{}, "Cannot send this type of data"); std::memcpy(gathered, values, nb_values); } template <typename T> inline void Communicator::gatherVImpl(T *, int *, int) const {} template <typename T> inline void Communicator::broadcastImpl(T *, int, int) const {} int Communicator::getMaxTag() const { return std::numeric_limits<int>::max(); } int Communicator::getMinTag() const { return 0; } } // namespace akantu diff --git a/src/synchronizer/communicator_event_handler.hh b/src/synchronizer/communicator_event_handler.hh index 9265521c7..f740ed40e 100644 --- a/src/synchronizer/communicator_event_handler.hh +++ b/src/synchronizer/communicator_event_handler.hh @@ -1,58 +1,61 @@ /** * @file communicator_event_handler.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Wed Nov 15 2017 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Nov 15 2017 * + * @brief Event handler of the communicator * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATOR_EVENT_HANDLER_HH__ #define __AKANTU_COMMUNICATOR_EVENT_HANDLER_HH__ namespace akantu { class Communicator; struct FinalizeCommunicatorEvent { explicit FinalizeCommunicatorEvent(const Communicator & comm) : communicator(comm) {} const Communicator & communicator; }; class CommunicatorEventHandler { public: virtual ~CommunicatorEventHandler() = default; virtual void onCommunicatorFinalize() = 0; private: inline void sendEvent(const FinalizeCommunicatorEvent &) { this->onCommunicatorFinalize(); } template <class EventHandler> friend class EventHandlerManager; }; } // akantu #endif /* __AKANTU_COMMUNICATOR_EVENT_HANDLER_HH__ */ diff --git a/src/synchronizer/communicator_inline_impl.hh b/src/synchronizer/communicator_inline_impl.hh index 3d669332b..7021cb145 100644 --- a/src/synchronizer/communicator_inline_impl.hh +++ b/src/synchronizer/communicator_inline_impl.hh @@ -1,88 +1,88 @@ /** - * @file static_communicator_inline_impl.hh + * @file communicator_inline_impl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Mon Sep 06 2010 - * @date last modification: Thu Dec 10 2015 + * @date creation: Tue Feb 02 2016 + * @date last modification: Tue Nov 07 2017 * * @brief implementation of inline functions * * @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) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "communicator.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STATIC_COMMUNICATOR_INLINE_IMPL_HH__ #define __AKANTU_STATIC_COMMUNICATOR_INLINE_IMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ inline void Communicator::freeCommunicationRequest(CommunicationRequest & request) const { request.free(); } /* -------------------------------------------------------------------------- */ inline void Communicator::freeCommunicationRequest( std::vector<CommunicationRequest> & requests) const { std::vector<CommunicationRequest>::iterator it; for (it = requests.begin(); it != requests.end(); ++it) { it->free(); } } /* -------------------------------------------------------------------------- */ template <typename T, typename MsgProcessor, typename TagGen> inline void Communicator::receiveAnyNumber( std::vector<CommunicationRequest> & send_requests, Array<T> receive_buffer, MsgProcessor && processor, TagGen && tag_gen) const { CommunicationRequest barrier_request; bool got_all = false, are_send_finished = false; while (not got_all) { bool are_receives_ready = true; while (are_receives_ready) { auto && tag = std::forward<TagGen>(tag_gen)(); CommunicationStatus status; are_receives_ready = asyncProbe<UInt>(_any_source, tag, status); if (are_receives_ready) { receive_buffer.resize(status.size()); receive(receive_buffer, status.getSource(), tag); std::forward<MsgProcessor>(processor)(status.getSource(), receive_buffer); } } if (not are_send_finished) { are_send_finished = testAll(send_requests); if (are_send_finished) barrier_request = asyncBarrier(); } if (are_send_finished) { got_all = test(barrier_request); } } } } // namespace akantu #endif /* __AKANTU_STATIC_COMMUNICATOR_INLINE_IMPL_HH__ */ diff --git a/src/synchronizer/communicator_mpi_inline_impl.cc b/src/synchronizer/communicator_mpi_inline_impl.cc index 9bd9fcf51..fda048047 100644 --- a/src/synchronizer/communicator_mpi_inline_impl.cc +++ b/src/synchronizer/communicator_mpi_inline_impl.cc @@ -1,460 +1,459 @@ /** - * @file static_communicator_mpi.cc + * @file communicator_mpi_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation: Sun Sep 26 2010 - * @date last modification: Thu Jan 21 2016 + * @date creation: Tue Nov 07 2017 + * @date last modification: Mon Dec 18 2017 * * @brief StaticCommunicatorMPI implementation * * @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) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "communicator.hh" #include "mpi_communicator_data.hh" /* -------------------------------------------------------------------------- */ #include <memory> #include <type_traits> #include <unordered_map> #include <vector> /* -------------------------------------------------------------------------- */ #include <mpi.h> /* -------------------------------------------------------------------------- */ #if (defined(__GNUC__) || defined(__GNUG__)) #if AKA_GCC_VERSION < 60000 namespace std { template <> struct hash<akantu::SynchronizerOperation> { using argument_type = akantu::SynchronizerOperation; size_t operator()(const argument_type & e) const noexcept { auto ue = underlying_type_t<argument_type>(e); return uh(ue); } private: const hash<underlying_type_t<argument_type>> uh{}; }; } // namespace std #endif #endif namespace akantu { class CommunicationRequestMPI : public InternalCommunicationRequest { public: CommunicationRequestMPI(UInt source, UInt dest) : InternalCommunicationRequest(source, dest), request(std::make_unique<MPI_Request>()) {} MPI_Request & getMPIRequest() { return *request; }; private: std::unique_ptr<MPI_Request> request; }; namespace { template <typename T> inline MPI_Datatype getMPIDatatype(); MPI_Op getMPISynchronizerOperation(const SynchronizerOperation & op) { std::unordered_map<SynchronizerOperation, MPI_Op> _operations{ {SynchronizerOperation::_sum, MPI_SUM}, {SynchronizerOperation::_min, MPI_MIN}, {SynchronizerOperation::_max, MPI_MAX}, {SynchronizerOperation::_prod, MPI_PROD}, {SynchronizerOperation::_land, MPI_LAND}, {SynchronizerOperation::_band, MPI_BAND}, {SynchronizerOperation::_lor, MPI_LOR}, {SynchronizerOperation::_bor, MPI_BOR}, {SynchronizerOperation::_lxor, MPI_LXOR}, {SynchronizerOperation::_bxor, MPI_BXOR}, {SynchronizerOperation::_min_loc, MPI_MINLOC}, {SynchronizerOperation::_max_loc, MPI_MAXLOC}, {SynchronizerOperation::_null, MPI_OP_NULL}}; return _operations[op]; } template <typename T> MPI_Datatype inline getMPIDatatype() { return MPI_DATATYPE_NULL; } #define SPECIALIZE_MPI_DATATYPE(type, mpi_type) \ template <> MPI_Datatype inline getMPIDatatype<type>() { return mpi_type; } #define COMMA , SPECIALIZE_MPI_DATATYPE(char, MPI_CHAR) SPECIALIZE_MPI_DATATYPE(float, MPI_FLOAT) SPECIALIZE_MPI_DATATYPE(double, MPI_DOUBLE) SPECIALIZE_MPI_DATATYPE(long double, MPI_LONG_DOUBLE) SPECIALIZE_MPI_DATATYPE(signed int, MPI_INT) SPECIALIZE_MPI_DATATYPE(NodeType, getMPIDatatype<Int>()) SPECIALIZE_MPI_DATATYPE(unsigned int, MPI_UNSIGNED) SPECIALIZE_MPI_DATATYPE(signed long int, MPI_LONG) SPECIALIZE_MPI_DATATYPE(unsigned long int, MPI_UNSIGNED_LONG) SPECIALIZE_MPI_DATATYPE(signed long long int, MPI_LONG_LONG) SPECIALIZE_MPI_DATATYPE(unsigned long long int, MPI_UNSIGNED_LONG_LONG) SPECIALIZE_MPI_DATATYPE(SCMinMaxLoc<double COMMA int>, MPI_DOUBLE_INT) SPECIALIZE_MPI_DATATYPE(SCMinMaxLoc<float COMMA int>, MPI_FLOAT_INT) SPECIALIZE_MPI_DATATYPE(bool, MPI_CXX_BOOL) inline int getMPISource(int src) { if (src == _any_source) return MPI_ANY_SOURCE; return src; } decltype(auto) convertRequests(std::vector<CommunicationRequest> & requests) { std::vector<MPI_Request> mpi_requests(requests.size()); for (auto && request_pair : zip(requests, mpi_requests)) { auto && req = std::get<0>(request_pair); auto && mpi_req = std::get<1>(request_pair); mpi_req = dynamic_cast<CommunicationRequestMPI &>(req.getInternal()) .getMPIRequest(); } return mpi_requests; } } // namespace // this is ugly but shorten the code a lot #define MPIDATA \ (*reinterpret_cast<MPICommunicatorData *>(communicator_data.get())) /* -------------------------------------------------------------------------- */ /* Implementation */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ Communicator::Communicator(int & /*argc*/, char **& /*argv*/, const private_member & /*unused*/) : communicator_data(std::make_unique<MPICommunicatorData>()) { prank = MPIDATA.rank(); psize = MPIDATA.size(); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::sendImpl(const T * buffer, Int size, Int receiver, Int tag, const CommunicationMode & mode) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Datatype type = getMPIDatatype<T>(); switch (mode) { case CommunicationMode::_auto: MPI_Send(buffer, size, type, receiver, tag, communicator); break; case CommunicationMode::_synchronous: MPI_Ssend(buffer, size, type, receiver, tag, communicator); break; case CommunicationMode::_ready: MPI_Rsend(buffer, size, type, receiver, tag, communicator); break; } } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::receiveImpl(T * buffer, Int size, Int sender, Int tag) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Status status; MPI_Datatype type = getMPIDatatype<T>(); MPI_Recv(buffer, size, type, getMPISource(sender), tag, communicator, &status); } /* -------------------------------------------------------------------------- */ template <typename T> CommunicationRequest Communicator::asyncSendImpl(const T * buffer, Int size, Int receiver, Int tag, const CommunicationMode & mode) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); auto * request = new CommunicationRequestMPI(prank, receiver); MPI_Request & req = request->getMPIRequest(); MPI_Datatype type = getMPIDatatype<T>(); switch (mode) { case CommunicationMode::_auto: MPI_Isend(buffer, size, type, receiver, tag, communicator, &req); break; case CommunicationMode::_synchronous: MPI_Issend(buffer, size, type, receiver, tag, communicator, &req); break; case CommunicationMode::_ready: MPI_Irsend(buffer, size, type, receiver, tag, communicator, &req); break; } return std::shared_ptr<InternalCommunicationRequest>(request); } /* -------------------------------------------------------------------------- */ template <typename T> CommunicationRequest Communicator::asyncReceiveImpl(T * buffer, Int size, Int sender, Int tag) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); auto * request = new CommunicationRequestMPI(sender, prank); MPI_Datatype type = getMPIDatatype<T>(); MPI_Request & req = request->getMPIRequest(); MPI_Irecv(buffer, size, type, getMPISource(sender), tag, communicator, &req); return std::shared_ptr<InternalCommunicationRequest>(request); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::probe(Int sender, Int tag, CommunicationStatus & status) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Status mpi_status; MPI_Probe(getMPISource(sender), tag, communicator, &mpi_status); MPI_Datatype type = getMPIDatatype<T>(); int count; MPI_Get_count(&mpi_status, type, &count); status.setSource(mpi_status.MPI_SOURCE); status.setTag(mpi_status.MPI_TAG); status.setSize(count); } /* -------------------------------------------------------------------------- */ template <typename T> bool Communicator::asyncProbe(Int sender, Int tag, CommunicationStatus & status) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Status mpi_status; int test; MPI_Iprobe(getMPISource(sender), tag, communicator, &test, &mpi_status); if (not test) return false; MPI_Datatype type = getMPIDatatype<T>(); int count; MPI_Get_count(&mpi_status, type, &count); status.setSource(mpi_status.MPI_SOURCE); status.setTag(mpi_status.MPI_TAG); status.setSize(count); return true; } /* -------------------------------------------------------------------------- */ bool Communicator::test(CommunicationRequest & request) const { MPI_Status status; int flag; auto & req_mpi = dynamic_cast<CommunicationRequestMPI &>(request.getInternal()); MPI_Request & req = req_mpi.getMPIRequest(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Test(&req, &flag, &status); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Test."); return (flag != 0); } /* -------------------------------------------------------------------------- */ bool Communicator::testAll(std::vector<CommunicationRequest> & requests) const { int are_finished; auto && mpi_requests = convertRequests(requests); MPI_Testall(mpi_requests.size(), mpi_requests.data(), &are_finished, MPI_STATUSES_IGNORE); return are_finished != 0 ? true : false; } /* -------------------------------------------------------------------------- */ void Communicator::wait(CommunicationRequest & request) const { MPI_Status status; auto & req_mpi = dynamic_cast<CommunicationRequestMPI &>(request.getInternal()); MPI_Request & req = req_mpi.getMPIRequest(); MPI_Wait(&req, &status); } /* -------------------------------------------------------------------------- */ void Communicator::waitAll(std::vector<CommunicationRequest> & requests) const { auto && mpi_requests = convertRequests(requests); MPI_Waitall(mpi_requests.size(), mpi_requests.data(), MPI_STATUSES_IGNORE); } /* -------------------------------------------------------------------------- */ UInt Communicator::waitAny(std::vector<CommunicationRequest> & requests) const { auto && mpi_requests = convertRequests(requests); int pos; MPI_Waitany(mpi_requests.size(), mpi_requests.data(), &pos, MPI_STATUSES_IGNORE); if (pos != MPI_UNDEFINED) { return pos; } else { return UInt(-1); } } /* -------------------------------------------------------------------------- */ void Communicator::barrier() const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Barrier(communicator); } /* -------------------------------------------------------------------------- */ CommunicationRequest Communicator::asyncBarrier() const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); auto * request = new CommunicationRequestMPI(0, 0); MPI_Request & req = request->getMPIRequest(); MPI_Ibarrier(communicator, &req); return std::shared_ptr<InternalCommunicationRequest>(request); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::reduceImpl(T * values, int nb_values, const SynchronizerOperation & op, int root) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Datatype type = getMPIDatatype<T>(); MPI_Reduce(MPI_IN_PLACE, values, nb_values, type, getMPISynchronizerOperation(op), root, communicator); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::allReduceImpl(T * values, int nb_values, const SynchronizerOperation & op) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Datatype type = getMPIDatatype<T>(); MPI_Allreduce(MPI_IN_PLACE, values, nb_values, type, getMPISynchronizerOperation(op), communicator); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::allGatherImpl(T * values, int nb_values) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Datatype type = getMPIDatatype<T>(); MPI_Allgather(MPI_IN_PLACE, nb_values, type, values, nb_values, type, communicator); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::allGatherVImpl(T * values, int * nb_values) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); std::vector<int> displs(psize); displs[0] = 0; for (int i = 1; i < psize; ++i) { displs[i] = displs[i - 1] + nb_values[i - 1]; } MPI_Datatype type = getMPIDatatype<T>(); MPI_Allgatherv(MPI_IN_PLACE, *nb_values, type, values, nb_values, displs.data(), type, communicator); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::gatherImpl(T * values, int nb_values, int root) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); T *send_buf = nullptr, *recv_buf = nullptr; if (prank == root) { send_buf = (T *)MPI_IN_PLACE; recv_buf = values; } else { send_buf = values; } MPI_Datatype type = getMPIDatatype<T>(); MPI_Gather(send_buf, nb_values, type, recv_buf, nb_values, type, root, communicator); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::gatherImpl(T * values, int nb_values, T * gathered, int nb_gathered) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); T * send_buf = values; T * recv_buf = gathered; if (nb_gathered == 0) nb_gathered = nb_values; MPI_Datatype type = getMPIDatatype<T>(); MPI_Gather(send_buf, nb_values, type, recv_buf, nb_gathered, type, this->prank, communicator); } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::gatherVImpl(T * values, int * nb_values, int root) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); int * displs = nullptr; if (prank == root) { displs = new int[psize]; displs[0] = 0; for (int i = 1; i < psize; ++i) { displs[i] = displs[i - 1] + nb_values[i - 1]; } } T *send_buf = nullptr, *recv_buf = nullptr; if (prank == root) { send_buf = (T *)MPI_IN_PLACE; recv_buf = values; } else send_buf = values; MPI_Datatype type = getMPIDatatype<T>(); MPI_Gatherv(send_buf, *nb_values, type, recv_buf, nb_values, displs, type, root, communicator); if (prank == root) { delete[] displs; } } /* -------------------------------------------------------------------------- */ template <typename T> void Communicator::broadcastImpl(T * values, int nb_values, int root) const { MPI_Comm communicator = MPIDATA.getMPICommunicator(); MPI_Datatype type = getMPIDatatype<T>(); MPI_Bcast(values, nb_values, type, root, communicator); } /* -------------------------------------------------------------------------- */ int Communicator::getMaxTag() const { return MPIDATA.getMaxTag(); } int Communicator::getMinTag() const { return 0; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/data_accessor.cc b/src/synchronizer/data_accessor.cc index 3a51a7016..e80b72ce3 100644 --- a/src/synchronizer/data_accessor.cc +++ b/src/synchronizer/data_accessor.cc @@ -1,155 +1,154 @@ /** * @file data_accessor.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Sun Oct 19 2014 + * @date last modification: Tue Feb 20 2018 * * @brief data accessors constructor functions * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "fe_engine.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T, bool pack_helper> void DataAccessor<Element>::packUnpackNodalDataHelper( Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh) { UInt nb_component = data.getNbComponent(); UInt nb_nodes_per_element = 0; ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt * conn = nullptr; for (auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; conn = mesh.getConnectivity(el.type, el.ghost_type).storage(); nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type); } UInt el_offset = el.element * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt offset_conn = conn[el_offset + n]; Vector<T> data_vect(data.storage() + offset_conn * nb_component, nb_component); if (pack_helper) buffer << data_vect; else buffer >> data_vect; } } } /* ------------------------------------------------------------------------ */ template <typename T, bool pack_helper> void DataAccessor<Element>::packUnpackElementalDataHelper( ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & element, bool per_quadrature_point_data, const FEEngine & fem) { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt nb_quad_per_elem = 0; UInt nb_component = 0; Array<T> * vect = nullptr; for (auto & el : element) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; vect = &data_to_pack(el.type, el.ghost_type); nb_quad_per_elem = per_quadrature_point_data ? fem.getNbIntegrationPoints(el.type, el.ghost_type) : 1; nb_component = vect->getNbComponent(); } Vector<T> data(vect->storage() + el.element * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem); if (pack_helper) buffer << data; else buffer >> data; } } /* -------------------------------------------------------------------------- */ template <typename T, bool pack_helper> void DataAccessor<UInt>::packUnpackDOFDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<UInt> & dofs) { T * data_ptr = data.storage(); for (const auto & dof : dofs) { if (pack_helper) buffer << data_ptr[dof]; else buffer >> data_ptr[dof]; } } /* -------------------------------------------------------------------------- */ #define DECLARE_HELPERS(T) \ template void DataAccessor<Element>::packUnpackNodalDataHelper<T, false>( \ Array<T> & data, CommunicationBuffer & buffer, \ const Array<Element> & elements, const Mesh & mesh); \ template void DataAccessor<Element>::packUnpackNodalDataHelper<T, true>( \ Array<T> & data, CommunicationBuffer & buffer, \ const Array<Element> & elements, const Mesh & mesh); \ template void \ DataAccessor<Element>::packUnpackElementalDataHelper<T, false>( \ ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, \ const Array<Element> & element, bool per_quadrature_point_data, \ const FEEngine & fem); \ template void DataAccessor<Element>::packUnpackElementalDataHelper<T, true>( \ ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, \ const Array<Element> & element, bool per_quadrature_point_data, \ const FEEngine & fem); \ template void DataAccessor<UInt>::packUnpackDOFDataHelper<T, true>( \ Array<T> & data, CommunicationBuffer & buffer, \ const Array<UInt> & dofs); \ template void DataAccessor<UInt>::packUnpackDOFDataHelper<T, false>( \ Array<T> & data, CommunicationBuffer & buffer, const Array<UInt> & dofs) /* -------------------------------------------------------------------------- */ DECLARE_HELPERS(Real); DECLARE_HELPERS(UInt); DECLARE_HELPERS(bool); /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/synchronizer/data_accessor.hh b/src/synchronizer/data_accessor.hh index cebcb66b3..78c956279 100644 --- a/src/synchronizer/data_accessor.hh +++ b/src/synchronizer/data_accessor.hh @@ -1,279 +1,278 @@ /** * @file data_accessor.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 01 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Sun Feb 04 2018 * * @brief Interface of accessors for pack_unpack system * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "communication_buffer.hh" #include "element.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DATA_ACCESSOR_HH__ #define __AKANTU_DATA_ACCESSOR_HH__ namespace akantu { class FEEngine; } // akantu namespace akantu { class DataAccessorBase { public: DataAccessorBase() = default; virtual ~DataAccessorBase() = default; }; template <class T> class DataAccessor : public virtual DataAccessorBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DataAccessor() = default; ~DataAccessor() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /** * @brief get the number of data to exchange for a given array of T * (elements or dofs) and a given akantu::SynchronizationTag */ virtual UInt getNbData(const Array<T> & elements, const SynchronizationTag & tag) const = 0; /** * @brief pack the data for a given array of T (elements or dofs) and a given * akantu::SynchronizationTag */ virtual void packData(CommunicationBuffer & buffer, const Array<T> & element, const SynchronizationTag & tag) const = 0; /** * @brief unpack the data for a given array of T (elements or dofs) and a * given akantu::SynchronizationTag */ virtual void unpackData(CommunicationBuffer & buffer, const Array<T> & element, const SynchronizationTag & tag) = 0; }; /* -------------------------------------------------------------------------- */ /* Specialization */ /* -------------------------------------------------------------------------- */ template <> class DataAccessor<Element> : public virtual DataAccessorBase { public: DataAccessor() = default; ~DataAccessor() override = default; virtual UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const = 0; virtual void packData(CommunicationBuffer & buffer, const Array<Element> & element, const SynchronizationTag & tag) const = 0; virtual void unpackData(CommunicationBuffer & buffer, const Array<Element> & element, const SynchronizationTag & tag) = 0; /* ------------------------------------------------------------------------ */ public: template <typename T, bool pack_helper> static void packUnpackNodalDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh); /* ------------------------------------------------------------------------ */ template <typename T, bool pack_helper> static void packUnpackElementalDataHelper( ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & element, bool per_quadrature_point_data, const FEEngine & fem); /* ------------------------------------------------------------------------ */ template <typename T> static void packNodalDataHelper(const Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh) { packUnpackNodalDataHelper<T, true>(const_cast<Array<T> &>(data), buffer, elements, mesh); } template <typename T> static inline void unpackNodalDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh) { packUnpackNodalDataHelper<T, false>(data, buffer, elements, mesh); } /* ------------------------------------------------------------------------ */ template <typename T> static inline void packElementalDataHelper(const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements, bool per_quadrature_point, const FEEngine & fem) { packUnpackElementalDataHelper<T, true>( const_cast<ElementTypeMapArray<T> &>(data_to_pack), buffer, elements, per_quadrature_point, fem); } template <typename T> static inline void unpackElementalDataHelper(ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements, bool per_quadrature_point, const FEEngine & fem) { packUnpackElementalDataHelper<T, false>(data_to_unpack, buffer, elements, per_quadrature_point, fem); } }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <> class DataAccessor<UInt> : public virtual DataAccessorBase { public: DataAccessor() = default; ~DataAccessor() override = default; virtual UInt getNbData(const Array<UInt> & elements, const SynchronizationTag & tag) const = 0; virtual void packData(CommunicationBuffer & buffer, const Array<UInt> & element, const SynchronizationTag & tag) const = 0; virtual void unpackData(CommunicationBuffer & buffer, const Array<UInt> & element, const SynchronizationTag & tag) = 0; /* ------------------------------------------------------------------------ */ public: template <typename T, bool pack_helper> static void packUnpackDOFDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<UInt> & dofs); template <typename T> static inline void packDOFDataHelper(const Array<T> & data_to_pack, CommunicationBuffer & buffer, const Array<UInt> & dofs) { packUnpackDOFDataHelper<T, true>(const_cast<Array<T> &>(data_to_pack), buffer, dofs); } template <typename T> static inline void unpackDOFDataHelper(Array<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<UInt> & dofs) { packUnpackDOFDataHelper<T, false>(data_to_unpack, buffer, dofs); } }; /* -------------------------------------------------------------------------- */ template <typename T> class AddOperation { public: inline T operator()(T & a, T & b) { return a + b; }; }; template <typename T> class IdentityOperation { public: inline T & operator()(T &, T & b) { return b; }; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <template <class> class Op, class T> class ReduceUIntDataAccessor : public virtual DataAccessor<UInt> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ReduceUIntDataAccessor(Array<T> & data, const SynchronizationTag & tag) : data(data), tag(tag) {} ~ReduceUIntDataAccessor() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ UInt getNbData(const Array<UInt> & elements, const SynchronizationTag & tag) const override { if (tag != this->tag) return 0; Vector<T> tmp(data.getNbComponent()); return elements.size() * CommunicationBuffer::sizeInBuffer(tmp); } /* ------------------------------------------------------------------------ */ void packData(CommunicationBuffer & buffer, const Array<UInt> & elements, const SynchronizationTag & tag) const override { if (tag != this->tag) return; auto data_it = data.begin(data.getNbComponent()); for (auto el : elements) { buffer << Vector<T>(data_it[el]); } } /* ------------------------------------------------------------------------ */ void unpackData(CommunicationBuffer & buffer, const Array<UInt> & elements, const SynchronizationTag & tag) override { if (tag != this->tag) return; auto data_it = data.begin(data.getNbComponent()); for (auto el : elements) { Vector<T> unpacked(data.getNbComponent()); Vector<T> vect(data_it[el]); buffer >> unpacked; vect = oper(vect, unpacked); } } protected: /// data to (un)pack Array<T> & data; /// Tag to consider SynchronizationTag tag; /// reduction operator Op<Vector<T>> oper; }; /* -------------------------------------------------------------------------- */ template <class T> using SimpleUIntDataAccessor = ReduceUIntDataAccessor<IdentityOperation, T>; } // akantu #endif /* __AKANTU_DATA_ACCESSOR_HH__ */ diff --git a/src/synchronizer/dof_synchronizer.cc b/src/synchronizer/dof_synchronizer.cc index 944332113..ed0a9bcf2 100644 --- a/src/synchronizer/dof_synchronizer.cc +++ b/src/synchronizer/dof_synchronizer.cc @@ -1,280 +1,279 @@ /** * @file dof_synchronizer.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 17 2011 - * @date last modification: Wed Oct 21 2015 + * @date last modification: Tue Feb 06 2018 * * @brief DOF synchronizing object implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_synchronizer.hh" #include "aka_iterators.hh" #include "dof_manager_default.hh" #include "mesh.hh" #include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /** * A DOFSynchronizer needs a mesh and the number of degrees of freedom * per node to be created. In the constructor computes the local and global dof * number for each dof. The member * proc_informations (std vector) is resized with the number of mpi * processes. Each entry in the vector is a PerProcInformations object * that contains the interactions of the current mpi process (prank) with the * mpi process corresponding to the position of that entry. Every * ProcInformations object contains one array with the dofs that have * to be sent to prank and a second one with dofs that willl be received form * prank. * This information is needed for the asychronous communications. The * constructor sets up this information. */ DOFSynchronizer::DOFSynchronizer(DOFManagerDefault & dof_manager, const ID & id, MemoryID memory_id) : SynchronizerImpl<UInt>(dof_manager.getCommunicator(), id, memory_id), root(0), dof_manager(dof_manager), root_dofs(0, 1, "dofs-to-receive-from-master"), dof_changed(true) { std::vector<ID> dof_ids = dof_manager.getDOFIDs(); // Transfers nodes to global equation numbers in new schemes for (const ID & dof_id : dof_ids) { registerDOFs(dof_id); } this->initScatterGatherCommunicationScheme(); } /* -------------------------------------------------------------------------- */ DOFSynchronizer::~DOFSynchronizer() = default; /* -------------------------------------------------------------------------- */ void DOFSynchronizer::registerDOFs(const ID & dof_id) { if (this->nb_proc == 1) return; if (dof_manager.getSupportType(dof_id) != _dst_nodal) return; using const_scheme_iterator = Communications<UInt>::const_scheme_iterator; const auto equation_numbers = dof_manager.getLocalEquationNumbers(dof_id); const auto & associated_nodes = dof_manager.getDOFsAssociatedNodes(dof_id); const auto & node_synchronizer = dof_manager.getMesh().getNodeSynchronizer(); const auto & node_communications = node_synchronizer.getCommunications(); auto transcode_node_to_global_dof_scheme = [this, &associated_nodes, &equation_numbers](const_scheme_iterator it, const_scheme_iterator end, const CommunicationSendRecv & sr) -> void { for (; it != end; ++it) { auto & scheme = communications.createScheme(it->first, sr); const auto & node_scheme = it->second; for (auto & node : node_scheme) { auto an_begin = associated_nodes.begin(); auto an_it = an_begin; auto an_end = associated_nodes.end(); std::vector<UInt> global_dofs_per_node; while ((an_it = std::find(an_it, an_end, node)) != an_end) { UInt pos = an_it - an_begin; UInt local_eq_num = equation_numbers(pos); UInt global_eq_num = dof_manager.localToGlobalEquationNumber(local_eq_num); global_dofs_per_node.push_back(global_eq_num); ++an_it; } std::sort(global_dofs_per_node.begin(), global_dofs_per_node.end()); std::transform(global_dofs_per_node.begin(), global_dofs_per_node.end(), global_dofs_per_node.begin(), [this](UInt g) -> UInt { UInt l = dof_manager.globalToLocalEquationNumber(g); return l; }); for (auto & leqnum : global_dofs_per_node) { scheme.push_back(leqnum); } } } }; for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { auto ncs_it = node_communications.begin_scheme(*sr_it); auto ncs_end = node_communications.end_scheme(*sr_it); transcode_node_to_global_dof_scheme(ncs_it, ncs_end, *sr_it); } dof_changed = true; } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::initScatterGatherCommunicationScheme() { AKANTU_DEBUG_IN(); if (this->nb_proc == 1) { dof_changed = false; AKANTU_DEBUG_OUT(); return; } UInt nb_dofs = dof_manager.getLocalSystemSize(); this->root_dofs.clear(); this->master_receive_dofs.clear(); Array<UInt> dofs_to_send; for (UInt n = 0; n < nb_dofs; ++n) { if (dof_manager.isLocalOrMasterDOF(n)) { auto & receive_per_proc = master_receive_dofs[this->root]; UInt global_dof = dof_manager.localToGlobalEquationNumber(n); root_dofs.push_back(n); receive_per_proc.push_back(global_dof); dofs_to_send.push_back(global_dof); } } if (this->rank == UInt(this->root)) { Array<UInt> nb_dof_per_proc(this->nb_proc); communicator.gather(dofs_to_send.size(), nb_dof_per_proc); std::vector<CommunicationRequest> requests; for (UInt p = 0; p < nb_proc; ++p) { if (p == UInt(this->root)) continue; auto & receive_per_proc = master_receive_dofs[p]; receive_per_proc.resize(nb_dof_per_proc(p)); if (nb_dof_per_proc(p) != 0) requests.push_back(communicator.asyncReceive( receive_per_proc, p, Tag::genTag(p, 0, Tag::_GATHER_INITIALIZATION, this->hash_id))); } communicator.waitAll(requests); communicator.freeCommunicationRequest(requests); } else { communicator.gather(dofs_to_send.size(), this->root); AKANTU_DEBUG(dblDebug, "I have " << nb_dofs << " dofs (" << dofs_to_send.size() << " to send to master proc"); if (dofs_to_send.size() != 0) communicator.send(dofs_to_send, this->root, Tag::genTag(this->rank, 0, Tag::_GATHER_INITIALIZATION, this->hash_id)); } dof_changed = false; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool DOFSynchronizer::hasChanged() { communicator.allReduce(dof_changed, SynchronizerOperation::_lor); return dof_changed; } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::onNodesAdded(const Array<UInt> & nodes_list) { auto dof_ids = dof_manager.getDOFIDs(); const auto & node_synchronizer = dof_manager.getMesh().getNodeSynchronizer(); const auto & node_communications = node_synchronizer.getCommunications(); std::set<UInt> relevant_nodes; std::map<UInt, std::vector<UInt>> nodes_per_proc[2]; for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { auto sit = node_communications.begin_scheme(*sr_it); auto send = node_communications.end_scheme(*sr_it); for (; sit != send; ++sit) { auto proc = sit->first; const auto & scheme = sit->second; for (auto node : nodes_list) { if (scheme.find(node) == UInt(-1)) continue; relevant_nodes.insert(node); nodes_per_proc[*sr_it][proc].push_back(node); } } } std::map<UInt, std::vector<UInt>> dofs_per_proc[2]; for (auto & dof_id : dof_ids) { const auto & associated_nodes = dof_manager.getDOFsAssociatedNodes(dof_id); const auto & local_equation_numbers = dof_manager.getEquationsNumbers(dof_id); for (auto tuple : zip(associated_nodes, local_equation_numbers)) { UInt assoc_node; UInt local_eq_num; std::tie(assoc_node, local_eq_num) = tuple; for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { for (auto & pair : nodes_per_proc[*sr_it]) { if (std::find(pair.second.end(), pair.second.end(), assoc_node) != pair.second.end()) { dofs_per_proc[*sr_it][pair.first].push_back(local_eq_num); } } } } } for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { for (auto & pair : dofs_per_proc[*sr_it]) { std::sort(pair.second.begin(), pair.second.end(), [this](UInt la, UInt lb) -> bool { UInt ga = dof_manager.localToGlobalEquationNumber(la); UInt gb = dof_manager.localToGlobalEquationNumber(lb); return ga < gb; }); auto & scheme = communications.getScheme(pair.first, *sr_it); for (auto leq : pair.second) { scheme.push_back(leq); } } } dof_changed = true; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/dof_synchronizer.hh b/src/synchronizer/dof_synchronizer.hh index 8fbd31a28..a5184a9e1 100644 --- a/src/synchronizer/dof_synchronizer.hh +++ b/src/synchronizer/dof_synchronizer.hh @@ -1,112 +1,111 @@ /** * @file dof_synchronizer.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 17 2011 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Synchronize Array of DOFs * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "synchronizer_impl.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Mesh; class DOFManagerDefault; } #ifndef __AKANTU_DOF_SYNCHRONIZER_HH__ #define __AKANTU_DOF_SYNCHRONIZER_HH__ namespace akantu { class DOFSynchronizer : public SynchronizerImpl<UInt> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DOFSynchronizer(DOFManagerDefault & dof_manager, const ID & id = "dof_synchronizer", MemoryID memory_id = 0); ~DOFSynchronizer() override; virtual void registerDOFs(const ID & dof_id); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template <typename T> /// Gather the DOF value on the root proccessor void gather(const Array<T> & to_gather, Array<T> & gathered); /// Gather the DOF value on the root proccessor template <typename T> void gather(const Array<T> & to_gather); /// Scatter a DOF Array form root to all processors template <typename T> void scatter(Array<T> & scattered, const Array<T> & to_scatter); /// Scatter a DOF Array form root to all processors template <typename T> void scatter(Array<T> & scattered); template <typename T> void synchronize(Array<T> & vector) const; template <template <class> class Op, typename T> void reduceSynchronize(Array<T> & vector) const; void onNodesAdded(const Array<UInt> & nodes); protected: /// check if dof changed set on at least one processor bool hasChanged(); /// init the scheme for scatter and gather operation, need extra memory void initScatterGatherCommunicationScheme(); Int getRank(const UInt & /*node*/) const final { AKANTU_TO_IMPLEMENT(); } private: /// Root processor for scatter/gather operations Int root; /// information on the dofs DOFManagerDefault & dof_manager; /// dofs from root Array<UInt> root_dofs; /// Dofs received from slaves proc (only on master) std::map<UInt, Array<UInt>> master_receive_dofs; bool dof_changed; }; } // akantu #include "dof_synchronizer_inline_impl.cc" #endif /* __AKANTU_DOF_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/dof_synchronizer_inline_impl.cc b/src/synchronizer/dof_synchronizer_inline_impl.cc index 9165512ca..1a6cd6d30 100644 --- a/src/synchronizer/dof_synchronizer_inline_impl.cc +++ b/src/synchronizer/dof_synchronizer_inline_impl.cc @@ -1,298 +1,297 @@ /** * @file dof_synchronizer_inline_impl.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 17 2011 - * @date last modification: Tue Dec 09 2014 + * @date last modification: Wed Nov 08 2017 * * @brief DOFSynchronizer inline implementation * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communication_buffer.hh" #include "data_accessor.hh" #include "dof_manager_default.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DOF_SYNCHRONIZER_INLINE_IMPL_CC__ #define __AKANTU_DOF_SYNCHRONIZER_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> void DOFSynchronizer::gather(const Array<T> & to_gather, Array<T> & gathered) { if (this->hasChanged()) initScatterGatherCommunicationScheme(); AKANTU_DEBUG_ASSERT(this->rank == UInt(this->root), "This function cannot be called on a slave processor"); AKANTU_DEBUG_ASSERT(to_gather.size() == this->dof_manager.getLocalSystemSize(), "The array to gather does not have the correct size"); AKANTU_DEBUG_ASSERT(gathered.size() == this->dof_manager.getSystemSize(), "The gathered array does not have the correct size"); if (this->nb_proc == 1) { gathered.copy(to_gather, true); AKANTU_DEBUG_OUT(); return; } std::map<UInt, CommunicationBuffer> buffers; std::vector<CommunicationRequest> requests; for (UInt p = 0; p < this->nb_proc; ++p) { if (p == UInt(this->root)) continue; auto receive_it = this->master_receive_dofs.find(p); AKANTU_DEBUG_ASSERT(receive_it != this->master_receive_dofs.end(), "Could not find the receive list for dofs of proc " << p); const Array<UInt> & receive_dofs = receive_it->second; if (receive_dofs.size() == 0) continue; CommunicationBuffer & buffer = buffers[p]; buffer.resize(receive_dofs.size() * to_gather.getNbComponent() * sizeof(T)); AKANTU_DEBUG_INFO( "Preparing to receive data for " << receive_dofs.size() << " dofs from processor " << p << " " << Tag::genTag(p, this->root, Tag::_GATHER, this->hash_id)); requests.push_back(communicator.asyncReceive( buffer, p, Tag::genTag(p, this->root, Tag::_GATHER, this->hash_id))); } auto data_gathered_it = gathered.begin(to_gather.getNbComponent()); { // copy master data auto data_to_gather_it = to_gather.begin(to_gather.getNbComponent()); for (auto local_dof : root_dofs) { UInt global_dof = dof_manager.localToGlobalEquationNumber(local_dof); Vector<T> dof_data_gathered = data_gathered_it[global_dof]; Vector<T> dof_data_to_gather = data_to_gather_it[local_dof]; dof_data_gathered = dof_data_to_gather; } } auto rr = UInt(-1); while ((rr = communicator.waitAny(requests)) != UInt(-1)) { CommunicationRequest & request = requests[rr]; UInt sender = request.getSource(); AKANTU_DEBUG_ASSERT(this->master_receive_dofs.find(sender) != this->master_receive_dofs.end() && buffers.find(sender) != buffers.end(), "Missing infos concerning proc " << sender); const Array<UInt> & receive_dofs = this->master_receive_dofs.find(sender)->second; CommunicationBuffer & buffer = buffers[sender]; for (auto global_dof : receive_dofs) { Vector<T> dof_data = data_gathered_it[global_dof]; buffer >> dof_data; } requests.erase(requests.begin() + rr); } } /* -------------------------------------------------------------------------- */ template <typename T> void DOFSynchronizer::gather(const Array<T> & to_gather) { AKANTU_DEBUG_IN(); if (this->hasChanged()) initScatterGatherCommunicationScheme(); AKANTU_DEBUG_ASSERT(this->rank != UInt(this->root), "This function cannot be called on the root processor"); AKANTU_DEBUG_ASSERT(to_gather.size() == this->dof_manager.getLocalSystemSize(), "The array to gather does not have the correct size"); if (this->root_dofs.size() == 0) { AKANTU_DEBUG_OUT(); return; } CommunicationBuffer buffer(this->root_dofs.size() * to_gather.getNbComponent() * sizeof(T)); auto data_it = to_gather.begin(to_gather.getNbComponent()); for (auto dof : this->root_dofs) { Vector<T> data = data_it[dof]; buffer << data; } AKANTU_DEBUG_INFO("Gathering data for " << to_gather.size() << " dofs on processor " << this->root << " " << Tag::genTag(this->rank, 0, Tag::_GATHER, this->hash_id)); communicator.send(buffer, this->root, Tag::genTag(this->rank, 0, Tag::_GATHER, this->hash_id)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void DOFSynchronizer::scatter(Array<T> & scattered, const Array<T> & to_scatter) { AKANTU_DEBUG_IN(); if (this->hasChanged()) initScatterGatherCommunicationScheme(); AKANTU_DEBUG_ASSERT(this->rank == UInt(this->root), "This function cannot be called on a slave processor"); AKANTU_DEBUG_ASSERT(scattered.size() == this->dof_manager.getLocalSystemSize(), "The scattered array does not have the correct size"); AKANTU_DEBUG_ASSERT(to_scatter.size() == this->dof_manager.getSystemSize(), "The array to scatter does not have the correct size"); if (this->nb_proc == 1) { scattered.copy(to_scatter, true); AKANTU_DEBUG_OUT(); return; } std::map<UInt, CommunicationBuffer> buffers; std::vector<CommunicationRequest> requests; for (UInt p = 0; p < nb_proc; ++p) { auto data_to_scatter_it = to_scatter.begin(to_scatter.getNbComponent()); if (p == this->rank) { auto data_scattered_it = scattered.begin(to_scatter.getNbComponent()); // copy the data for the local processor for (auto local_dof : root_dofs) { auto global_dof = dof_manager.localToGlobalEquationNumber(local_dof); Vector<T> dof_data_to_scatter = data_to_scatter_it[global_dof]; Vector<T> dof_data_scattered = data_scattered_it[local_dof]; dof_data_scattered = dof_data_to_scatter; } continue; } const Array<UInt> & receive_dofs = this->master_receive_dofs.find(p)->second; // prepare the send buffer CommunicationBuffer & buffer = buffers[p]; buffer.resize(receive_dofs.size() * scattered.getNbComponent() * sizeof(T)); // pack the data for (auto global_dof : receive_dofs) { Vector<T> dof_data_to_scatter = data_to_scatter_it[global_dof]; buffer << dof_data_to_scatter; } // send the data requests.push_back(communicator.asyncSend( buffer, p, Tag::genTag(p, 0, Tag::_SCATTER, this->hash_id))); } // wait a clean communications communicator.waitAll(requests); communicator.freeCommunicationRequest(requests); // synchronize slave and ghost nodes synchronize(scattered); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void DOFSynchronizer::scatter(Array<T> & scattered) { AKANTU_DEBUG_IN(); if (this->hasChanged()) this->initScatterGatherCommunicationScheme(); AKANTU_DEBUG_ASSERT(this->rank != UInt(this->root), "This function cannot be called on the root processor"); AKANTU_DEBUG_ASSERT(scattered.size() == this->dof_manager.getLocalSystemSize(), "The scattered array does not have the correct size"); // prepare the data auto data_scattered_it = scattered.begin(scattered.getNbComponent()); CommunicationBuffer buffer(this->root_dofs.size() * scattered.getNbComponent() * sizeof(T)); // receive the data communicator.receive( buffer, this->root, Tag::genTag(this->rank, 0, Tag::_SCATTER, this->hash_id)); // unpack the data for (auto local_dof : root_dofs) { Vector<T> dof_data_scattered = data_scattered_it[local_dof]; buffer >> dof_data_scattered; } // synchronize the ghosts synchronize(scattered); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void DOFSynchronizer::synchronize(Array<T> & dof_values_to_synchronize) const { AKANTU_DEBUG_IN(); SimpleUIntDataAccessor<T> data_accessor(dof_values_to_synchronize, _gst_whatever); this->synchronizeOnce(data_accessor, _gst_whatever); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <template <class> class Op, typename T> void DOFSynchronizer::reduceSynchronize(Array<T> & dof_vector) const { AKANTU_DEBUG_IN(); ReduceUIntDataAccessor<Op, T> data_accessor(dof_vector, _gst_whatever); this->synchronizeOnce(data_accessor, _gst_whatever); AKANTU_DEBUG_OUT(); } } // akantu #endif /* __AKANTU_DOF_SYNCHRONIZER_INLINE_IMPL_CC__ */ diff --git a/src/synchronizer/element_info_per_processor.cc b/src/synchronizer/element_info_per_processor.cc index a1ae4e5a4..b39152c38 100644 --- a/src/synchronizer/element_info_per_processor.cc +++ b/src/synchronizer/element_info_per_processor.cc @@ -1,109 +1,110 @@ /** * @file element_info_per_processor.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Mar 11 14:56:42 2016 + * @date creation: Wed Mar 16 2016 + * @date last modification: Tue Nov 07 2017 * - * @brief + * @brief Helper class to distribute a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_info_per_processor.hh" #include "communicator.hh" #include "element_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <iostream> #include <map> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ElementInfoPerProc::ElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type) : MeshAccessor(synchronizer.getMesh()), synchronizer(synchronizer), rank(synchronizer.getCommunicator().whoAmI()), nb_proc(synchronizer.getCommunicator().getNbProc()), root(root), type(type), message_count(message_cnt), mesh(synchronizer.getMesh()), comm(synchronizer.getCommunicator()) {} /* -------------------------------------------------------------------------- */ void ElementInfoPerProc::fillCommunicationScheme( const Array<UInt> & partition) { AKANTU_DEBUG_IN(); Element element; element.type = this->type; auto & communications = this->synchronizer.getCommunications(); auto part = partition.begin(); std::map<UInt, Array<Element>> send_array_per_proc; for (UInt lel = 0; lel < nb_local_element; ++lel) { UInt nb_send = *part; ++part; element.element = lel; element.ghost_type = _not_ghost; for (UInt p = 0; p < nb_send; ++p, ++part) { UInt proc = *part; AKANTU_DEBUG(dblAccessory, "Must send : " << element << " to proc " << proc); send_array_per_proc[proc].push_back(element); } } for (auto & send_schemes : send_array_per_proc) { if (send_schemes.second.size() == 0) continue; auto & scheme = communications.createSendScheme(send_schemes.first); scheme.append(send_schemes.second); } std::map<UInt, Array<Element>> recv_array_per_proc; for (UInt gel = 0; gel < nb_ghost_element; ++gel, ++part) { UInt proc = *part; element.element = gel; element.ghost_type = _ghost; AKANTU_DEBUG(dblAccessory, "Must recv : " << element << " from proc " << proc); recv_array_per_proc[proc].push_back(element); } for (auto & recv_schemes : recv_array_per_proc) { if (recv_schemes.second.size() == 0) continue; auto & scheme = communications.createRecvScheme(recv_schemes.first); scheme.append(recv_schemes.second); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/element_info_per_processor.hh b/src/synchronizer/element_info_per_processor.hh index df7c8c21b..a31e70d41 100644 --- a/src/synchronizer/element_info_per_processor.hh +++ b/src/synchronizer/element_info_per_processor.hh @@ -1,144 +1,145 @@ /** * @file element_info_per_processor.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Mar 11 14:45:15 2016 + * @date creation: Wed Mar 16 2016 + * @date last modification: Tue Nov 07 2017 * * @brief Helper classes to create the distributed synchronizer and distribute - * a mesh + * a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "communication_buffer.hh" #include "mesh.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ #define __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ namespace akantu { class ElementSynchronizer; class Communicator; class MeshPartition; } /* -------------------------------------------------------------------------- */ namespace akantu { class ElementInfoPerProc : protected MeshAccessor { public: ElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type); virtual void synchronizeConnectivities() = 0; virtual void synchronizePartitions() = 0; virtual void synchronizeTags() = 0; virtual void synchronizeGroups() = 0; protected: void fillCommunicationScheme(const Array<UInt> & partition); template <class CommunicationBuffer> void fillElementGroupsFromBuffer(CommunicationBuffer & buffer); template <typename T, typename BufferType> void fillMeshDataTemplated(BufferType & buffer, const std::string & tag_name, UInt nb_component); template <typename BufferType> void fillMeshData(BufferType & buffer, const std::string & tag_name, const MeshDataTypeCode & type_code, UInt nb_component); protected: ElementSynchronizer & synchronizer; UInt rank{0}; UInt nb_proc{1}; UInt root{0}; ElementType type{_not_defined}; UInt nb_tags{0}; UInt nb_nodes_per_element{0}; UInt nb_element{0}; UInt nb_local_element{0}; UInt nb_ghost_element{0}; UInt message_count{0}; Mesh & mesh; const Communicator & comm; }; /* -------------------------------------------------------------------------- */ class MasterElementInfoPerProc : protected ElementInfoPerProc { public: MasterElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type, const MeshPartition & partition); void synchronizeConnectivities() override; void synchronizePartitions() override; void synchronizeTags() override; void synchronizeGroups() override; protected: template <typename T> void fillTagBufferTemplated(std::vector<DynamicCommunicationBuffer> & buffers, const std::string & tag_name); void fillTagBuffer(std::vector<DynamicCommunicationBuffer> & buffers, const std::string & tag_name); private: const MeshPartition & partition; Vector<UInt> all_nb_local_element; Vector<UInt> all_nb_ghost_element; Vector<UInt> all_nb_element_to_send; }; /* -------------------------------------------------------------------------- */ class SlaveElementInfoPerProc : protected ElementInfoPerProc { public: SlaveElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root); void synchronizeConnectivities() override; void synchronizePartitions() override; void synchronizeTags() override; void synchronizeGroups() override; bool needSynchronize(); private: UInt nb_element_to_receive{0}; }; } // akantu #include "element_info_per_processor_tmpl.hh" #endif /* __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ */ diff --git a/src/synchronizer/element_info_per_processor_tmpl.hh b/src/synchronizer/element_info_per_processor_tmpl.hh index 299a61f4a..3fb055721 100644 --- a/src/synchronizer/element_info_per_processor_tmpl.hh +++ b/src/synchronizer/element_info_per_processor_tmpl.hh @@ -1,145 +1,147 @@ /** * @file element_info_per_processor_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Mar 11 15:03:12 2016 + * @date creation: Wed Mar 16 2016 + * @date last modification: Tue Feb 20 2018 * - * @brief + * @brief Helper classes to create the distributed synchronizer and distribute + * a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_group.hh" #include "element_info_per_processor.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ #define __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T, typename BufferType> void ElementInfoPerProc::fillMeshDataTemplated(BufferType & buffer, const std::string & tag_name, UInt nb_component) { AKANTU_DEBUG_ASSERT(this->mesh.getNbElement(this->type) == nb_local_element, "Did not got enought informations for the tag " << tag_name << " and the element type " << this->type << ":" << "_not_ghost." << " Got " << nb_local_element << " values, expected " << mesh.getNbElement(this->type)); MeshData & mesh_data = this->getMeshData(); mesh_data.registerElementalData<T>(tag_name); Array<T> & data = mesh_data.getElementalDataArrayAlloc<T>( tag_name, this->type, _not_ghost, nb_component); data.resize(nb_local_element); /// unpacking the data, element by element for (UInt i(0); i < nb_local_element; ++i) { for (UInt j(0); j < nb_component; ++j) { buffer >> data(i, j); } } AKANTU_DEBUG_ASSERT(mesh.getNbElement(this->type, _ghost) == nb_ghost_element, "Did not got enought informations for the tag " << tag_name << " and the element type " << this->type << ":" << "_ghost." << " Got " << nb_ghost_element << " values, expected " << mesh.getNbElement(this->type, _ghost)); Array<T> & data_ghost = mesh_data.getElementalDataArrayAlloc<T>( tag_name, this->type, _ghost, nb_component); data_ghost.resize(nb_ghost_element); /// unpacking the ghost data, element by element for (UInt j(0); j < nb_ghost_element; ++j) { for (UInt k(0); k < nb_component; ++k) { buffer >> data_ghost(j, k); } } } /* -------------------------------------------------------------------------- */ template <typename BufferType> void ElementInfoPerProc::fillMeshData(BufferType & buffer, const std::string & tag_name, const MeshDataTypeCode & type_code, UInt nb_component) { #define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ fillMeshDataTemplated<BOOST_PP_TUPLE_ELEM(2, 1, elem)>(buffer, tag_name, \ nb_component); \ break; \ } switch (type_code) { BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , AKANTU_MESH_DATA_TYPES) default: AKANTU_ERROR("Could not determine the type of tag" << tag_name << "!"); break; } #undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA } /* -------------------------------------------------------------------------- */ template <class CommunicationBuffer> void ElementInfoPerProc::fillElementGroupsFromBuffer( CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); Element el; el.type = type; for (auto ghost_type : ghost_types) { UInt nb_element = mesh.getNbElement(type, ghost_type); el.ghost_type = ghost_type; for (UInt e = 0; e < nb_element; ++e) { el.element = e; std::vector<std::string> element_to_group; buffer >> element_to_group; AKANTU_DEBUG_ASSERT(e < mesh.getNbElement(type, ghost_type), "The mesh does not have the element " << e); for (auto && element : element_to_group) { mesh.getElementGroup(element).add(el, false, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ */ diff --git a/src/synchronizer/element_synchronizer.cc b/src/synchronizer/element_synchronizer.cc index 32698e302..a0e65e5cc 100644 --- a/src/synchronizer/element_synchronizer.cc +++ b/src/synchronizer/element_synchronizer.cc @@ -1,369 +1,368 @@ /** * @file element_synchronizer.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Sep 01 2010 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Tue Feb 20 2018 * * @brief implementation of a communicator using a static_communicator for * real * send/receive * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "aka_common.hh" #include "mesh.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <iostream> #include <map> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ElementSynchronizer::ElementSynchronizer(Mesh & mesh, const ID & id, MemoryID memory_id, bool register_to_event_manager, EventHandlerPriority event_priority) : SynchronizerImpl<Element>(mesh.getCommunicator(), id, memory_id), mesh(mesh), element_to_prank("element_to_prank", id, memory_id) { AKANTU_DEBUG_IN(); if (register_to_event_manager) this->mesh.registerEventHandler(*this, event_priority); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementSynchronizer::ElementSynchronizer(const ElementSynchronizer & other, const ID & id, bool register_to_event_manager, EventHandlerPriority event_priority) : SynchronizerImpl<Element>(other, id), mesh(other.mesh), element_to_prank("element_to_prank", id, other.memory_id) { AKANTU_DEBUG_IN(); element_to_prank.copy(other.element_to_prank); if (register_to_event_manager) this->mesh.registerEventHandler(*this, event_priority); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementSynchronizer::~ElementSynchronizer() = default; /* -------------------------------------------------------------------------- */ void ElementSynchronizer::substituteElements( const std::map<Element, Element> & old_to_new_elements) { auto found_element_end = old_to_new_elements.end(); // substitute old elements with new ones for (auto && sr : iterate_send_recv) { for (auto && scheme_pair : communications.iterateSchemes(sr)) { auto & list = scheme_pair.second; for (auto & el : list) { auto found_element_it = old_to_new_elements.find(el); if (found_element_it != found_element_end) el = found_element_it->second; } } } } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::onElementsChanged( const Array<Element> & old_elements_list, const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) { // create a map to link old elements to new ones std::map<Element, Element> old_to_new_elements; for (UInt el = 0; el < old_elements_list.size(); ++el) { AKANTU_DEBUG_ASSERT(old_to_new_elements.find(old_elements_list(el)) == old_to_new_elements.end(), "The same element cannot appear twice in the list"); old_to_new_elements[old_elements_list(el)] = new_elements_list(el); } substituteElements(old_to_new_elements); communications.invalidateSizes(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::onElementsRemoved( const Array<Element> & element_to_remove, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent &) { AKANTU_DEBUG_IN(); this->removeElements(element_to_remove); this->renumberElements(new_numbering); communications.invalidateSizes(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::buildElementToPrank() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); element_to_prank.initialize(mesh, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined, _with_nb_element = true, _default_value = rank); /// assign prank to all ghost elements for (auto && scheme : communications.iterateSchemes(_recv)) { auto & recv = scheme.second; auto proc = scheme.first; for (auto & element : recv) { element_to_prank(element) = proc; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Int ElementSynchronizer::getRank(const Element & element) const { if (not element_to_prank.exists(element.type, element.ghost_type)) { // Nicolas: Ok This is nasty I know.... const_cast<ElementSynchronizer *>(this)->buildElementToPrank(); } return element_to_prank(element); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::reset() { AKANTU_DEBUG_IN(); communications.resetSchemes(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::removeElements( const Array<Element> & element_to_remove) { AKANTU_DEBUG_IN(); std::vector<CommunicationRequest> send_requests; std::map<UInt, Array<UInt>> list_of_elements_per_proc; auto filter_list = [](const Array<UInt> & keep, Array<Element> & list) { Array<Element> new_list; for (UInt e = 0; e < keep.size() - 1; ++e) { Element & el = list(keep(e)); new_list.push_back(el); } list.copy(new_list); }; // Handling ghost elements for (auto && scheme_pair : communications.iterateSchemes(_recv)) { auto proc = scheme_pair.first; auto & recv = scheme_pair.second; Array<UInt> & keep_list = list_of_elements_per_proc[proc]; auto rem_it = element_to_remove.begin(); auto rem_end = element_to_remove.end(); for (auto && pair : enumerate(recv)) { const auto & el = std::get<1>(pair); auto pos = std::find(rem_it, rem_end, el); if (pos == rem_end) { keep_list.push_back(std::get<0>(pair)); } } keep_list.push_back(UInt(-1)); // To no send empty arrays auto && tag = Tag::genTag(proc, 0, Tag::_MODIFY_SCHEME, this->hash_id); AKANTU_DEBUG_INFO("Sending a message of size " << keep_list.size() << " to proc " << proc << " TAG(" << tag << ")"); send_requests.push_back(this->communicator.asyncSend(keep_list, proc, tag)); #ifndef AKANTU_NDEBUG auto old_size = recv.size(); #endif filter_list(keep_list, recv); AKANTU_DEBUG_INFO("I had " << old_size << " elements to recv from proc " << proc << " and " << keep_list.size() << " elements to keep. I have " << recv.size() << " elements left."); } for (auto && scheme_pair : communications.iterateSchemes(_send)) { auto proc = scheme_pair.first; auto & send = scheme_pair.second; CommunicationStatus status; auto && tag = Tag::genTag(rank, 0, Tag::_MODIFY_SCHEME, this->hash_id); AKANTU_DEBUG_INFO("Getting number of elements of proc " << proc << " to keep - TAG(" << tag << ")"); this->communicator.probe<UInt>(proc, tag, status); Array<UInt> keep_list(status.size()); AKANTU_DEBUG_INFO("Receiving list of elements (" << keep_list.size() << " elements) to keep for proc " << proc << " TAG(" << tag << ")"); this->communicator.receive(keep_list, proc, tag); #ifndef AKANTU_NDEBUG auto old_size = send.size(); #endif filter_list(keep_list, send); AKANTU_DEBUG_INFO("I had " << old_size << " elements to send to proc " << proc << " and " << keep_list.size() << " elements to keep. I have " << send.size() << " elements left."); } this->communicator.waitAll(send_requests); this->communicator.freeCommunicationRequest(send_requests); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::renumberElements( const ElementTypeMapArray<UInt> & new_numbering) { for (auto && sr : iterate_send_recv) { for (auto && scheme_pair : communications.iterateSchemes(sr)) { auto & list = scheme_pair.second; for (auto && el : list) { if (new_numbering.exists(el.type, el.ghost_type)) el.element = new_numbering(el); } } } } /* -------------------------------------------------------------------------- */ UInt ElementSynchronizer::sanityCheckDataSize( const Array<Element> & elements, const SynchronizationTag &) const { UInt size = 0; size += sizeof(SynchronizationTag); // tag size += sizeof(UInt); // comm_desc.getNbData(); size += sizeof(UInt); // comm_desc.getProc(); size += sizeof(UInt); // mesh.getCommunicator().whoAmI(); // barycenters size += (elements.size() * mesh.getSpatialDimension() * sizeof(Real)); return size; } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::packSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const { auto & buffer = comm_desc.getBuffer(); buffer << comm_desc.getTag(); buffer << comm_desc.getNbData(); buffer << comm_desc.getProc(); buffer << mesh.getCommunicator().whoAmI(); auto & send_element = comm_desc.getScheme(); /// pack barycenters in debug mode for (auto && element : send_element) { Vector<Real> barycenter(mesh.getSpatialDimension()); mesh.getBarycenter(element, barycenter); buffer << barycenter; } } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::unpackSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const { auto & buffer = comm_desc.getBuffer(); const auto & tag = comm_desc.getTag(); auto nb_data = comm_desc.getNbData(); auto proc = comm_desc.getProc(); auto rank = mesh.getCommunicator().whoAmI(); decltype(nb_data) recv_nb_data; decltype(proc) recv_proc; decltype(rank) recv_rank; SynchronizationTag t; buffer >> t; buffer >> recv_nb_data; buffer >> recv_proc; buffer >> recv_rank; AKANTU_DEBUG_ASSERT( t == tag, "The tag received does not correspond to the tag expected"); AKANTU_DEBUG_ASSERT( nb_data == recv_nb_data, "The nb_data received does not correspond to the nb_data expected"); AKANTU_DEBUG_ASSERT(UInt(recv_rank) == proc, "The rank received does not correspond to the proc"); AKANTU_DEBUG_ASSERT(recv_proc == UInt(rank), "The proc received does not correspond to the rank"); auto & recv_element = comm_desc.getScheme(); auto spatial_dimension = mesh.getSpatialDimension(); for (auto && element : recv_element) { Vector<Real> barycenter_loc(spatial_dimension); mesh.getBarycenter(element, barycenter_loc); Vector<Real> barycenter(spatial_dimension); buffer >> barycenter; auto dist = barycenter_loc.distance(barycenter); if (not Math::are_float_equal(dist, 0.)) AKANTU_EXCEPTION("Unpacking an unknown value for the element " << element << "(barycenter " << barycenter_loc << " != buffer " << barycenter << ") [" << dist << "] - tag: " << tag << " comm from " << proc << " to " << rank); } } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/element_synchronizer.hh b/src/synchronizer/element_synchronizer.hh index 8764beb79..d72058515 100644 --- a/src/synchronizer/element_synchronizer.hh +++ b/src/synchronizer/element_synchronizer.hh @@ -1,216 +1,215 @@ /** * @file element_synchronizer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Main element synchronizer * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_SYNCHRONIZER_HH__ #define __AKANTU_ELEMENT_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "mesh_partition.hh" #include "synchronizer_impl.hh" namespace akantu { class Mesh; } /* -------------------------------------------------------------------------- */ namespace akantu { class ElementSynchronizer : public SynchronizerImpl<Element>, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ElementSynchronizer(Mesh & mesh, const ID & id = "element_synchronizer", MemoryID memory_id = 0, bool register_to_event_manager = true, EventHandlerPriority event_priority = _ehp_synchronizer); ElementSynchronizer(const ElementSynchronizer & other, const ID & id = "element_synchronizer_copy", bool register_to_event_manager = true, EventHandlerPriority event_priority = _ehp_synchronizer); public: ~ElementSynchronizer() override; friend class ElementInfoPerProc; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /// mesh event handler onElementsChanged void onElementsChanged(const Array<Element> & old_elements_list, const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> & new_numbering, const ChangedElementsEvent & event) override; /// mesh event handler onRemovedElement void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; /// mesh event handler onNodesAdded void onNodesAdded(const Array<UInt> & /* nodes_list*/, const NewNodesEvent & /*event*/) override{}; /// mesh event handler onRemovedNodes void onNodesRemoved(const Array<UInt> & /*nodes_list*/, const Array<UInt> & /*new_numbering*/, const RemovedNodesEvent & /*event*/) override{}; /// mesh event handler onElementsAdded void onElementsAdded(const Array<Element> & /*elements_list*/, const NewElementsEvent & /*event*/) override{}; protected: /// reset send and recv element lists void reset(); /// remove elements from the synchronizer without renumbering them void removeElements(const Array<Element> & element_to_remove); /// renumber the elements in the synchronizer void renumberElements(const ElementTypeMapArray<UInt> & new_numbering); /// build processor to element correspondence void buildElementToPrank(); protected: /// fill the nodes type vector void fillNodesType(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num); template <typename T> void fillTagBufferTemplated(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition); void fillTagBuffer(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition); /// function that handels the MeshData to be split (root side) static void synchronizeTagsSend(ElementSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_local_element, UInt nb_ghost_element); /// function that handles the MeshData to be split (other nodes) static void synchronizeTagsRecv(ElementSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, UInt nb_local_element, UInt nb_ghost_element); /// function that handles the preexisting groups in the mesh static void synchronizeElementGroups(ElementSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_element); /// function that handles the preexisting groups in the mesh static void synchronizeElementGroups(ElementSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsMaster(ElementSynchronizer & communicator, UInt root, Mesh & mesh); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsSlaves(ElementSynchronizer & communicator, UInt root, Mesh & mesh); template <class CommunicationBuffer> static void fillNodeGroupsFromBuffer(ElementSynchronizer & communicator, Mesh & mesh, CommunicationBuffer & buffer); /// substitute elements in the send and recv arrays void substituteElements(const std::map<Element, Element> & old_to_new_elements); /* ------------------------------------------------------------------------ */ /* Sanity checks */ /* ------------------------------------------------------------------------ */ UInt sanityCheckDataSize(const Array<Element> & elements, const SynchronizationTag & tag) const override; /* ------------------------------------------------------------------------ */ void packSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const override; /* ------------------------------------------------------------------------ */ void unpackSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Mesh, mesh, Mesh &); AKANTU_GET_MACRO(ElementToRank, element_to_prank, const ElementTypeMapArray<Int> &); Int getRank(const Element & element) const final; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// reference to the underlying mesh Mesh & mesh; friend class FacetSynchronizer; ElementTypeMapArray<Int> element_to_prank; }; /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_ELEMENT_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/facet_synchronizer.cc b/src/synchronizer/facet_synchronizer.cc index 9fef0f160..6c65293ee 100644 --- a/src/synchronizer/facet_synchronizer.cc +++ b/src/synchronizer/facet_synchronizer.cc @@ -1,514 +1,531 @@ /** * @file facet_synchronizer.cc * + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * + * @date creation: Wed Nov 05 2014 + * @date last modification: Fri Jan 26 2018 * * @brief Facet synchronizer for parallel simulations with cohesive elments * * @section LICENSE * - * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 <http://www.gnu.org/licenses/>. + * */ + /* -------------------------------------------------------------------------- */ #include "facet_synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ FacetSynchronizer::FacetSynchronizer( Mesh & mesh, const ElementSynchronizer & element_synchronizer, const ID & id, MemoryID memory_id) : ElementSynchronizer(mesh, id, memory_id) { const auto & comm = mesh.getCommunicator(); auto spatial_dimension = mesh.getSpatialDimension(); element_to_prank.initialize(mesh, _spatial_dimension = spatial_dimension - 1, _ghost_type = _ghost, _with_nb_element = true, _default_value = rank); for (auto && scheme_pair : element_synchronizer.communications.iterateSchemes(_recv)) { auto proc = std::get<0>(scheme_pair); const auto & scheme = std::get<1>(scheme_pair); for (auto && elem : scheme) { const auto & facet_to_element = mesh.getSubelementToElement(elem.type, elem.ghost_type); Vector<Element> facets = facet_to_element.begin( facet_to_element.getNbComponent())[elem.element]; for (UInt f = 0; f < facets.size(); ++f) { auto & facet = facets(f); if (facet == ElementNull) continue; if (facet.ghost_type == _not_ghost) continue; auto & facet_rank = element_to_prank(facet); if ((proc < UInt(facet_rank)) || (UInt(facet_rank) == rank)) facet_rank = proc; } } } ElementTypeMapArray<UInt> facet_global_connectivities( "facet_global_connectivities", id, memory_id); facet_global_connectivities.initialize( mesh, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _with_nb_nodes_per_element = true); mesh.getGlobalConnectivity(facet_global_connectivities); /// init facet check tracking ElementTypeMapArray<bool> facet_checked("facet_checked", id, memory_id); std::vector<CommunicationRequest> send_requests; std::map<UInt, ElementTypeMapArray<UInt>> send_facets; std::map<UInt, ElementTypeMapArray<UInt>> connectivities; for (auto && sr : iterate_send_recv) { GhostType interesting_ghost_type = sr == _send ? _not_ghost : _ghost; for (auto && scheme_pair : element_synchronizer.communications.iterateSchemes(sr)) { facet_checked.initialize(mesh, _spatial_dimension = spatial_dimension - 1, _ghost_type = interesting_ghost_type, _with_nb_element = true, _default_value = false); auto && proc = scheme_pair.first; auto & elements = scheme_pair.second; auto & facet_scheme = communications.createScheme(proc, sr); // this creates empty arrays... auto & facet_send_elements = send_facets[proc]; auto & connectivities_for_proc = connectivities[proc]; if (sr == _send) { connectivities_for_proc.setID(id + ":connectivities_for_proc:"); connectivities_for_proc.initialize( mesh, _spatial_dimension = spatial_dimension - 1, _with_nb_nodes_per_element = true); facet_send_elements.setID(id + ":facet_send_elements"); facet_send_elements.initialize( mesh, _spatial_dimension = spatial_dimension - 1); } for (auto && element : elements) { const auto & facet_to_element = mesh.getSubelementToElement(element.type, element.ghost_type); Vector<Element> facets = facet_to_element.begin( facet_to_element.getNbComponent())[element.element]; for (UInt f = 0; f < facets.size(); ++f) { auto & facet = facets(f); if (facet == ElementNull) continue; if (facet.ghost_type != interesting_ghost_type) continue; if (sr == _recv && UInt(element_to_prank(facet)) != proc) continue; auto & checked = facet_checked(facet); if (checked) continue; checked = true; if (sr == _recv) { facet_scheme.push_back(facet); } else { facet_send_elements(facet.type, facet.ghost_type) .push_back(facet.element); } auto & global_conn = facet_global_connectivities(facet.type, facet.ghost_type); Vector<UInt> conn = global_conn.begin(global_conn.getNbComponent())[facet.element]; std::sort(conn.storage(), conn.storage() + conn.size()); connectivities_for_proc(facet.type, facet.ghost_type).push_back(conn); } } } } /// do every communication by element type for (auto && type : mesh.elementTypes(spatial_dimension - 1)) { for (auto && pair : connectivities) { auto proc = std::get<0>(pair); const auto & connectivities_for_proc = std::get<1>(pair); auto && tag = Tag::genTag(proc, proc, 1337); send_requests.push_back( comm.asyncSend(connectivities_for_proc(type, _ghost), proc, tag, CommunicationMode::_synchronous)); } auto nb_nodes_per_facet = Mesh::getNbNodesPerElement(type); Array<UInt> buffer; Element facet{type, 0, _not_ghost}; comm.receiveAnyNumber( send_requests, buffer, [&](auto && proc, auto && message) { auto & local_connectivities = connectivities[proc](type, _not_ghost); auto & list = send_facets[proc](type, _not_ghost); auto & send_scheme = communications.getScheme(proc, _send); std::vector<bool> checked(list.size(), false); for (auto && c_to_match : make_view(message, nb_nodes_per_facet)) { #if !defined(AKANTU_NDEBUG) bool found = false; #endif for (auto && pair : enumerate( make_view(local_connectivities, nb_nodes_per_facet))) { UInt f; Vector<UInt> local_conn; std::tie(f, local_conn) = pair; if (checked[f]) continue; if (c_to_match == local_conn) { #if !defined(AKANTU_NDEBUG) found = true; #endif checked[f] = true; facet.element = list(f); send_scheme.push_back(facet); break; } } AKANTU_DEBUG_ASSERT(found, "facet not found"); } }, [&]() { return Tag::genTag(rank, rank, 1337); }); } } // /* -------------------------------------------------------------------------- // */ void FacetSynchronizer::setupFacetSynchronization( // ElementSynchronizer & distributed_synchronizer) { // AKANTU_DEBUG_IN(); // Array<Element> * distrib_send_element = // distributed_synchronizer.send_element; Array<Element> * // distrib_recv_element = distributed_synchronizer.recv_element; // /// build rank to facet correspondance // ElementTypeMapArray<UInt> rank_to_facet("rank_to_facet", id); // initRankToFacet(rank_to_facet); // buildRankToFacet(rank_to_facet, distrib_recv_element); // /// generate temp_send/recv element arrays with their connectivity // Array<ElementTypeMapArray<UInt> *> temp_send_element(nb_proc); // Array<ElementTypeMapArray<UInt> *> temp_recv_element(nb_proc); // Array<ElementTypeMapArray<UInt> *> send_connectivity(nb_proc); // Array<ElementTypeMapArray<UInt> *> recv_connectivity(nb_proc); // UInt spatial_dimension = mesh.getSpatialDimension(); // for (UInt p = 0; p < nb_proc; ++p) { // if (p == rank) // continue; // std::stringstream sstr; // sstr << p; // temp_send_element(p) = new ElementTypeMapArray<UInt>( // "temp_send_element_proc_" + sstr.str(), id); // mesh.initElementTypeMapArray(*temp_send_element(p), 1, // spatial_dimension - 1); // temp_recv_element(p) = new ElementTypeMapArray<UInt>( // "temp_recv_element_proc_" + sstr.str(), id); // mesh.initElementTypeMapArray(*temp_recv_element(p), 1, // spatial_dimension - 1); // send_connectivity(p) = new ElementTypeMapArray<UInt>( // "send_connectivity_proc_" + sstr.str(), id); // mesh.initElementTypeMapArray(*send_connectivity(p), 1, // spatial_dimension - 1, true); // recv_connectivity(p) = new ElementTypeMapArray<UInt>( // "recv_connectivity_proc_" + sstr.str(), id); // mesh.initElementTypeMapArray(*recv_connectivity(p), 1, // spatial_dimension - 1, true); // } // /// build global connectivity arrays // getFacetGlobalConnectivity<_not_ghost>(distributed_synchronizer, // rank_to_facet, distrib_send_element, // send_connectivity, // temp_send_element); // getFacetGlobalConnectivity<_ghost>(distributed_synchronizer, rank_to_facet, // distrib_recv_element, recv_connectivity, // temp_recv_element); // /// build send/recv facet arrays // buildSendElementList(send_connectivity, recv_connectivity, // temp_send_element); buildRecvElementList(temp_recv_element); // #ifndef AKANTU_NDEBUG // /// count recv facets for each processor // Array<UInt> nb_facets_recv(nb_proc); // nb_facets_recv.clear(); // Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, _ghost); // Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, _ghost); // for (; first != last; ++first) { // const Array<UInt> & r_to_f = rank_to_facet(*first, _ghost); // UInt nb_facet = r_to_f.getSize(); // for (UInt f = 0; f < nb_facet; ++f) { // UInt proc = r_to_f(f); // if (proc != rank) // ++nb_facets_recv(proc); // } // } // for (UInt p = 0; p < nb_proc; ++p) { // AKANTU_DEBUG_ASSERT(nb_facets_recv(p) == recv_element[p].getSize(), // "Wrong number of recv facets"); // } // #endif // for (UInt p = 0; p < nb_proc; ++p) { // delete temp_send_element(p); // delete temp_recv_element(p); // delete send_connectivity(p); // delete recv_connectivity(p); // } // AKANTU_DEBUG_OUT(); // } // /* -------------------------------------------------------------------------- // */ void FacetSynchronizer::buildSendElementList( // const Array<ElementTypeMapArray<UInt> *> & send_connectivity, // const Array<ElementTypeMapArray<UInt> *> & recv_connectivity, // const Array<ElementTypeMapArray<UInt> *> & temp_send_element) { // AKANTU_DEBUG_IN(); // StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); // UInt spatial_dimension = mesh.getSpatialDimension(); // GhostType ghost_type = _ghost; // Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, // ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension - // 1, ghost_type); // /// do every communication by element type // for (; first != last; ++first) { // ElementType facet_type = *first; // std::vector<CommunicationRequest *> send_requests; // UInt * send_size = new UInt[nb_proc]; // /// send asynchronous data // for (UInt p = 0; p < nb_proc; ++p) { // if (p == rank) // continue; // const Array<UInt> & recv_conn = // (*recv_connectivity(p))(facet_type, _ghost); // send_size[p] = recv_conn.getSize(); // /// send connectivity size // send_requests.push_back( // comm.asyncSend(send_size + p, 1, p, Tag::genTag(rank, p, 0))); // /// send connectivity data // send_requests.push_back(comm.asyncSend( // recv_conn.storage(), recv_conn.getSize() * // recv_conn.getNbComponent(), p, Tag::genTag(rank, p, 1))); // } // UInt * recv_size = new UInt[nb_proc]; // UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(facet_type); // /// receive data // for (UInt p = 0; p < nb_proc; ++p) { // if (p == rank) // continue; // /// receive connectivity size // comm.receive(recv_size + p, 1, p, Tag::genTag(p, rank, 0)); // Array<UInt> conn_to_match(recv_size[p], nb_nodes_per_facet); // /// receive connectivity // comm.receive(conn_to_match.storage(), // conn_to_match.getSize() * conn_to_match.getNbComponent(), // p, Tag::genTag(p, rank, 1)); // const Array<UInt> & send_conn = // (*send_connectivity(p))(facet_type, _not_ghost); // const Array<UInt> & list = // (*temp_send_element(p))(facet_type, _not_ghost); // UInt nb_local_facets = send_conn.getSize(); // AKANTU_DEBUG_ASSERT(nb_local_facets == list.getSize(), // "connectivity and facet list have different // sizes"); // Array<bool> checked(nb_local_facets); // checked.clear(); // Element facet(facet_type, 0, _not_ghost, _ek_regular); // Array<UInt>::iterator<Vector<UInt>> c_to_match_it = // conn_to_match.begin(nb_nodes_per_facet); // Array<UInt>::iterator<Vector<UInt>> c_to_match_end = // conn_to_match.end(nb_nodes_per_facet); // /// for every sent facet of other processors, find the // /// corresponding one in the local send connectivity data in // /// order to build the send_element arrays // for (; c_to_match_it != c_to_match_end; ++c_to_match_it) { // Array<UInt>::const_iterator<Vector<UInt>> c_local_it = // send_conn.begin(nb_nodes_per_facet); // Array<UInt>::const_iterator<Vector<UInt>> c_local_end = // send_conn.end(nb_nodes_per_facet); // for (UInt f = 0; f < nb_local_facets; ++f, ++c_local_it) { // if (checked(f)) // continue; // if ((*c_to_match_it) == (*c_local_it)) { // checked(f) = true; // facet.element = list(f); // send_element[p].push_back(facet); // break; // } // } // AKANTU_DEBUG_ASSERT(c_local_it != c_local_end, "facet not found"); // } // } // /// wait for all communications to be done and free the // /// communication request array // comm.waitAll(send_requests); // comm.freeCommunicationRequest(send_requests); // delete[] send_size; // delete[] recv_size; // } // AKANTU_DEBUG_OUT(); // } // /* -------------------------------------------------------------------------- // */ void FacetSynchronizer::buildRecvElementList( // const Array<ElementTypeMapArray<UInt> *> & temp_recv_element) { // AKANTU_DEBUG_IN(); // UInt spatial_dimension = mesh.getSpatialDimension(); // for (UInt p = 0; p < nb_proc; ++p) { // if (p == rank) // continue; // GhostType ghost_type = _ghost; // Mesh::type_iterator first = // mesh.firstType(spatial_dimension - 1, ghost_type); // Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, // ghost_type); // for (; first != last; ++first) { // ElementType facet_type = *first; // const Array<UInt> & list = // (*temp_recv_element(p))(facet_type, ghost_type); // UInt nb_local_facets = list.getSize(); // Element facet(facet_type, 0, ghost_type, _ek_regular); // for (UInt f = 0; f < nb_local_facets; ++f) { // facet.element = list(f); // recv_element[p].push_back(facet); // } // } // } // AKANTU_DEBUG_OUT(); // } // void FacetSynchronizer::initRankToFacet( // ElementTypeMapArray<UInt> & rank_to_facet) { // AKANTU_DEBUG_IN(); // auto spatial_dimension = mesh.getSpatialDimension(); // for (; first != last; ++first) { // ElementType type = *first; // UInt nb_facet = mesh.getNbElement(type, ghost_type); // Array<UInt> & rank_to_f = rank_to_facet(type, ghost_type); // rank_to_f.resize(nb_facet); // for (UInt f = 0; f < nb_facet; ++f) // rank_to_f(f) = rank; // } // AKANTU_DEBUG_OUT(); // } // /* -------------------------------------------------------------------------- // */ void FacetSynchronizer::buildRankToFacet( // ElementTypeMapArray<UInt> & rank_to_facet, // const Array<Element> * elements) { // AKANTU_DEBUG_IN(); // for (UInt p = 0; p < nb_proc; ++p) { // if (p == rank) // continue; // const Array<Element> & elem = elements[p]; // UInt nb_element = elem.getSize(); // for (UInt el = 0; el < nb_element; ++el) { // ElementType type = elem(el).type; // GhostType gt = elem(el).ghost_type; // UInt el_index = elem(el).element; // const Array<Element> & facet_to_element = // mesh.getSubelementToElement(type, gt); // UInt nb_facets_per_element = Mesh::getNbFacetsPerElement(type); // ElementType facet_type = Mesh::getFacetType(type); // for (UInt f = 0; f < nb_facets_per_element; ++f) { // const Element & facet = facet_to_element(el_index, f); // if (facet == ElementNull) // continue; // UInt facet_index = facet.element; // GhostType facet_gt = facet.ghost_type; // if (facet_gt == _not_ghost) // continue; // Array<UInt> & t_to_f = rank_to_facet(facet_type, facet_gt); // if ((p < t_to_f(facet_index)) || (t_to_f(facet_index) == rank)) // t_to_f(facet_index) = p; // } // } // } // AKANTU_DEBUG_OUT(); // } } // namespace akantu diff --git a/src/synchronizer/facet_synchronizer_inline_impl.cc b/src/synchronizer/facet_synchronizer_inline_impl.cc index 35656bd14..7d5c21329 100644 --- a/src/synchronizer/facet_synchronizer_inline_impl.cc +++ b/src/synchronizer/facet_synchronizer_inline_impl.cc @@ -1,127 +1,143 @@ /** * @file facet_synchronizer_inline_impl.cc * + * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * + * @date creation: Wed Nov 05 2014 + * @date last modification: Tue Nov 07 2017 * * @brief facet synchronizer inline implementation * * @section LICENSE * - * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2015-2018 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 <http://www.gnu.org/licenses/>. + * */ /* -------------------------------------------------------------------------- */ // template<GhostType ghost_facets> // inline void FacetSynchronizer::getFacetGlobalConnectivity(const // DistributedSynchronizer & distributed_synchronizer, // const // ElementTypeMapArray<UInt> // & rank_to_facet, // const Array<Element> * // elements, // Array<ElementTypeMapArray<UInt> // *> & connectivity, // Array<ElementTypeMapArray<UInt> // *> & facets) { // AKANTU_DEBUG_IN(); // UInt spatial_dimension = mesh.getSpatialDimension(); // /// init facet check tracking // ElementTypeMapArray<bool> facet_checked("facet_checked", id); // mesh.initElementTypeMapArray(facet_checked, 1, spatial_dimension - 1); // Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, // ghost_facets); // Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, // ghost_facets); // for (; first != last; ++first) { // ElementType type = *first; // Array<bool> & f_checked = facet_checked(type, ghost_facets); // UInt nb_facet = mesh.getNbElement(type, ghost_facets); // f_checked.resize(nb_facet); // } // const Array<UInt> & nodes_global_ids = // distributed_synchronizer.mesh.getGlobalNodesIds(); // /// loop on every processor // for (UInt p = 0; p < nb_proc; ++p) { // if (p == rank) continue; // /// reset facet check // Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, // ghost_facets); // Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, // ghost_facets); // for (; first != last; ++first) { // ElementType type = *first; // Array<bool> & f_checked = facet_checked(type, ghost_facets); // f_checked.clear(); // } // ElementTypeMapArray<UInt> & global_conn = (*connectivity(p)); // const Array<Element> & elem = elements[p]; // ElementTypeMapArray<UInt> & facet_list = (*facets(p)); // UInt nb_element = elem.getSize(); // /// loop on every send/recv element // for (UInt el = 0; el < nb_element; ++el) { // ElementType type = elem(el).type; // GhostType gt = elem(el).ghost_type; // UInt el_index = elem(el).element; // const Array<Element> & facet_to_element = // mesh.getSubelementToElement(type, gt); // UInt nb_facets_per_element = Mesh::getNbFacetsPerElement(type); // ElementType facet_type = Mesh::getFacetType(type); // UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(facet_type); // Vector<UInt> conn_tmp(nb_nodes_per_facet); // /// loop on every facet of the element // for (UInt f = 0; f < nb_facets_per_element; ++f) { // const Element & facet = facet_to_element(el_index, f); // if (facet == ElementNull) continue; // UInt facet_index = facet.element; // GhostType facet_gt = facet.ghost_type; // const Array<UInt> & t_to_f = rank_to_facet(facet_type, facet_gt); // /// exclude not ghost facets, facets assigned to other // /// processors // if (facet_gt != ghost_facets) continue; // if ((facet_gt == _ghost) && (t_to_f(facet_index) != p)) continue; // /// exclude facets that have already been added // Array<bool> & f_checked = facet_checked(facet_type, facet_gt); // if (f_checked(facet_index)) continue; // else f_checked(facet_index) = true; // /// add facet index // Array<UInt> & f_list = facet_list(facet_type, facet_gt); // f_list.push_back(facet_index); // /// add sorted facet global connectivity // const Array<UInt> & conn = mesh.getConnectivity(facet_type, facet_gt); // Array<UInt> & g_conn = global_conn(facet_type, facet_gt); // for (UInt n = 0; n < nb_nodes_per_facet; ++n) // conn_tmp(n) = nodes_global_ids(conn(facet_index, n)); // std::sort(conn_tmp.storage(), conn_tmp.storage() + nb_nodes_per_facet); // g_conn.push_back(conn_tmp); // } // } // } // AKANTU_DEBUG_OUT(); // } diff --git a/src/synchronizer/grid_synchronizer.cc b/src/synchronizer/grid_synchronizer.cc index 2a2896e8f..1c4045304 100644 --- a/src/synchronizer/grid_synchronizer.cc +++ b/src/synchronizer/grid_synchronizer.cc @@ -1,543 +1,542 @@ /** * @file grid_synchronizer.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Oct 03 2011 - * @date last modification: Fri Jan 22 2016 + * @date last modification: Tue Nov 07 2017 * * @brief implementation of the grid synchronizer * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "grid_synchronizer.hh" #include "aka_grid_dynamic.hh" #include "communicator.hh" #include "fe_engine.hh" #include "integration_point.hh" #include "mesh.hh" #include "mesh_io.hh" #include <iostream> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <class E> void GridSynchronizer::createGridSynchronizer(const SpatialGrid<E> & grid) { AKANTU_DEBUG_IN(); const Communicator & comm = this->mesh.getCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); if (nb_proc == 1) return; UInt spatial_dimension = this->mesh.getSpatialDimension(); Tensor3<Real> bounding_boxes(spatial_dimension, 2, nb_proc); Matrix<Real> my_bounding_box = bounding_boxes(my_rank); const auto & lower = grid.getLowerBounds(); const auto & upper = grid.getUpperBounds(); const auto & spacing = grid.getSpacing(); Vector<Real>(my_bounding_box(0)) = lower - spacing; Vector<Real>(my_bounding_box(1)) = upper + spacing; AKANTU_DEBUG_INFO( "Exchange of bounding box to detect the overlapping regions."); comm.allGather(bounding_boxes); std::vector<bool> intersects_proc(nb_proc); std::fill(intersects_proc.begin(), intersects_proc.end(), true); Matrix<Int> first_cells(spatial_dimension, nb_proc); Matrix<Int> last_cells(spatial_dimension, nb_proc); std::map<UInt, ElementTypeMapArray<UInt>> element_per_proc; // check the overlapping between my box and the one from other processors for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank) continue; Matrix<Real> proc_bounding_box = bounding_boxes(p); bool intersects = false; Vector<Int> first_cell_p = first_cells(p); Vector<Int> last_cell_p = last_cells(p); for (UInt s = 0; s < spatial_dimension; ++s) { // check overlapping of grid intersects = Math::intersects(my_bounding_box(s, 0), my_bounding_box(s, 1), proc_bounding_box(s, 0), proc_bounding_box(s, 1)); intersects_proc[p] = intersects_proc[p] & intersects; if (intersects) { AKANTU_DEBUG_INFO("I intersects with processor " << p << " in direction " << s); // is point 1 of proc p in the dimension s in the range ? bool point1 = Math::is_in_range(proc_bounding_box(s, 0), my_bounding_box(s, 0), my_bounding_box(s, 1)); // is point 2 of proc p in the dimension s in the range ? bool point2 = Math::is_in_range(proc_bounding_box(s, 1), my_bounding_box(s, 0), my_bounding_box(s, 1)); Real start = 0.; Real end = 0.; if (point1 && !point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box(s, 0); end = my_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 1 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else if (point1 && point2) { /* |-----------------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box(s, 0); end = proc_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 2 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else if (!point1 && point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box(s, 0); end = proc_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 3 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else { /* |-----------| my_bounding_box(i) * |-----------------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box(s, 0); end = my_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 4 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } first_cell_p(s) = grid.getCellID(start, s); last_cell_p(s) = grid.getCellID(end, s); } } // create the list of cells in the overlapping using CellID = typename SpatialGrid<E>::CellID; std::vector<CellID> cell_ids; if (intersects_proc[p]) { AKANTU_DEBUG_INFO("I intersects with processor " << p); CellID cell_id(spatial_dimension); // for (UInt i = 0; i < spatial_dimension; ++i) { // if(first_cell_p[i] != 0) --first_cell_p[i]; // if(last_cell_p[i] != 0) ++last_cell_p[i]; // } for (Int fd = first_cell_p(0); fd <= last_cell_p(0); ++fd) { cell_id.setID(0, fd); if (spatial_dimension == 1) { cell_ids.push_back(cell_id); } else { for (Int sd = first_cell_p(1); sd <= last_cell_p(1); ++sd) { cell_id.setID(1, sd); if (spatial_dimension == 2) { cell_ids.push_back(cell_id); } else { for (Int ld = first_cell_p(2); ld <= last_cell_p(2); ++ld) { cell_id.setID(2, ld); cell_ids.push_back(cell_id); } } } } } // get the list of elements in the cells of the overlapping std::set<Element> to_send; for (auto & cur_cell_id : cell_ids) { auto & cell = grid.getCell(cur_cell_id); for (auto & element : cell) { to_send.insert(element); } } AKANTU_DEBUG_INFO("I have prepared " << to_send.size() << " elements to send to processor " << p); auto & scheme = this->getCommunications().createSendScheme(p); std::stringstream sstr; sstr << "element_per_proc_" << p; element_per_proc.emplace( std::piecewise_construct, std::forward_as_tuple(p), std::forward_as_tuple(sstr.str(), id, memory_id)); ElementTypeMapArray<UInt> & elempproc = element_per_proc[p]; for (auto elem : to_send) { ElementType type = elem.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); // /!\ this part must be slow due to the access in the // ElementTypeMapArray<UInt> if (!elempproc.exists(type, _not_ghost)) elempproc.alloc(0, nb_nodes_per_element, type, _not_ghost); Vector<UInt> global_connect(nb_nodes_per_element); Vector<UInt> local_connect = mesh.getConnectivity(type).begin( nb_nodes_per_element)[elem.element]; for (UInt i = 0; i < nb_nodes_per_element; ++i) { global_connect(i) = mesh.getNodeGlobalId(local_connect(i)); AKANTU_DEBUG_ASSERT( global_connect(i) < mesh.getNbGlobalNodes(), "This global node send in the connectivity does not seem correct " << global_connect(i) << " corresponding to " << local_connect(i) << " from element " << elem.element); } elempproc(type).push_back(global_connect); scheme.push_back(elem); } } } AKANTU_DEBUG_INFO("I have finished to compute intersection," << " no it's time to communicate with my neighbors"); /** * Sending loop, sends the connectivity asynchronously to all concerned proc */ std::vector<CommunicationRequest> isend_requests; Tensor3<UInt> space(2, _max_element_type, nb_proc); for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank) continue; if (not intersects_proc[p]) continue; Matrix<UInt> info_proc = space(p); auto & elempproc = element_per_proc[p]; UInt count = 0; for (auto type : elempproc.elementTypes(_all_dimensions, _not_ghost)) { Array<UInt> & conn = elempproc(type, _not_ghost); Vector<UInt> info = info_proc((UInt)type); info[0] = (UInt)type; info[1] = conn.size() * conn.getNbComponent(); AKANTU_DEBUG_INFO( "I have " << conn.size() << " elements of type " << type << " to send to processor " << p << " (communication tag : " << Tag::genTag(my_rank, count, DATA_TAG) << ")"); isend_requests.push_back( comm.asyncSend(info, p, Tag::genTag(my_rank, count, SIZE_TAG))); if (info[1] != 0) isend_requests.push_back(comm.asyncSend<UInt>( conn, p, Tag::genTag(my_rank, count, DATA_TAG))); ++count; } Vector<UInt> info = info_proc((UInt)_not_defined); info[0] = (UInt)_not_defined; info[1] = 0; isend_requests.push_back( comm.asyncSend(info, p, Tag::genTag(my_rank, count, SIZE_TAG))); } /** * Receives the connectivity and store them in the ghosts elements */ MeshAccessor mesh_accessor(mesh); auto & global_nodes_ids = mesh_accessor.getNodesGlobalIds(); auto & nodes_type = mesh_accessor.getNodesType(); std::vector<CommunicationRequest> isend_nodes_requests; Vector<UInt> nb_nodes_to_recv(nb_proc); UInt nb_total_nodes_to_recv = 0; UInt nb_current_nodes = global_nodes_ids.size(); NewNodesEvent new_nodes; NewElementsEvent new_elements; std::map<UInt, std::vector<UInt>> ask_nodes_per_proc; for (UInt p = 0; p < nb_proc; ++p) { nb_nodes_to_recv(p) = 0; if (p == my_rank) continue; if (!intersects_proc[p]) continue; auto & scheme = this->getCommunications().createRecvScheme(p); ask_nodes_per_proc.emplace(std::piecewise_construct, std::forward_as_tuple(p), std::forward_as_tuple(0)); auto & ask_nodes = ask_nodes_per_proc[p]; UInt count = 0; ElementType type = _not_defined; do { Vector<UInt> info(2); comm.receive(info, p, Tag::genTag(p, count, SIZE_TAG)); type = (ElementType)info[0]; if (type == _not_defined) break; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt nb_element = info[1] / nb_nodes_per_element; Array<UInt> tmp_conn(nb_element, nb_nodes_per_element); tmp_conn.clear(); if (info[1] != 0) comm.receive<UInt>(tmp_conn, p, Tag::genTag(p, count, DATA_TAG)); AKANTU_DEBUG_INFO("I will receive " << nb_element << " elements of type " << ElementType(info[0]) << " from processor " << p << " (communication tag : " << Tag::genTag(p, count, DATA_TAG) << ")"); auto & ghost_connectivity = mesh_accessor.getConnectivity(type, _ghost); auto & ghost_counter = mesh_accessor.getGhostsCounters(type, _ghost); UInt nb_ghost_element = ghost_connectivity.size(); Element element{type, 0, _ghost}; Vector<UInt> conn(nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el) { UInt nb_node_to_ask_for_elem = 0; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt gn = tmp_conn(el, n); UInt ln = global_nodes_ids.find(gn); AKANTU_DEBUG_ASSERT(gn < mesh.getNbGlobalNodes(), "This global node seems not correct " << gn << " from element " << el << " node " << n); if (ln == UInt(-1)) { global_nodes_ids.push_back(gn); nodes_type.push_back(_nt_pure_gost); // pure ghost node ln = nb_current_nodes; new_nodes.getList().push_back(ln); ++nb_current_nodes; ask_nodes.push_back(gn); ++nb_node_to_ask_for_elem; } conn[n] = ln; } // all the nodes are already known locally, the element should // already exists auto c = UInt(-1); if (nb_node_to_ask_for_elem == 0) { c = ghost_connectivity.find(conn); element.element = c; } if (c == UInt(-1)) { element.element = nb_ghost_element; ++nb_ghost_element; ghost_connectivity.push_back(conn); ghost_counter.push_back(1); new_elements.getList().push_back(element); } else { ++ghost_counter(c); } scheme.push_back(element); } count++; } while (type != _not_defined); AKANTU_DEBUG_INFO("I have " << ask_nodes.size() << " missing nodes for elements coming from processor " << p << " (communication tag : " << Tag::genTag(my_rank, 0, ASK_NODES_TAG) << ")"); ask_nodes.push_back(UInt(-1)); isend_nodes_requests.push_back( comm.asyncSend(ask_nodes, p, Tag::genTag(my_rank, 0, ASK_NODES_TAG))); nb_nodes_to_recv(p) = ask_nodes.size() - 1; nb_total_nodes_to_recv += nb_nodes_to_recv(p); } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); /** * Sends requested nodes to proc */ auto & nodes = const_cast<Array<Real> &>(mesh.getNodes()); UInt nb_nodes = nodes.size(); std::vector<CommunicationRequest> isend_coordinates_requests; std::map<UInt, Array<Real>> nodes_to_send_per_proc; for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank || !intersects_proc[p]) continue; Array<UInt> asked_nodes; CommunicationStatus status; AKANTU_DEBUG_INFO("Waiting list of nodes to send to processor " << p << "(communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.probe<UInt>(p, Tag::genTag(p, 0, ASK_NODES_TAG), status); UInt nb_nodes_to_send = status.size(); asked_nodes.resize(nb_nodes_to_send); AKANTU_DEBUG_INFO("I have " << nb_nodes_to_send - 1 << " nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); AKANTU_DEBUG_INFO("Getting list of nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.receive(asked_nodes, p, Tag::genTag(p, 0, ASK_NODES_TAG)); nb_nodes_to_send--; asked_nodes.resize(nb_nodes_to_send); nodes_to_send_per_proc.emplace(std::piecewise_construct, std::forward_as_tuple(p), std::forward_as_tuple(0, spatial_dimension)); auto & nodes_to_send = nodes_to_send_per_proc[p]; auto node_it = nodes.begin(spatial_dimension); for (UInt n = 0; n < nb_nodes_to_send; ++n) { UInt ln = global_nodes_ids.find(asked_nodes(n)); AKANTU_DEBUG_ASSERT(ln != UInt(-1), "The node [" << asked_nodes(n) << "] requested by proc " << p << " was not found locally!"); nodes_to_send.push_back(node_it + ln); } if (nb_nodes_to_send != 0) { AKANTU_DEBUG_INFO("Sending the " << nb_nodes_to_send << " nodes to processor " << p << " (communication tag : " << Tag::genTag(p, 0, SEND_NODES_TAG) << ")"); isend_coordinates_requests.push_back(comm.asyncSend( nodes_to_send, p, Tag::genTag(my_rank, 0, SEND_NODES_TAG))); } #if not defined(AKANTU_NDEBUG) else { AKANTU_DEBUG_INFO("No nodes to send to processor " << p); } #endif } comm.waitAll(isend_nodes_requests); comm.freeCommunicationRequest(isend_nodes_requests); nodes.resize(nb_total_nodes_to_recv + nb_nodes); for (UInt p = 0; p < nb_proc; ++p) { if ((p != my_rank) && (nb_nodes_to_recv(p) > 0)) { AKANTU_DEBUG_INFO("Receiving the " << nb_nodes_to_recv(p) << " nodes from processor " << p << " (communication tag : " << Tag::genTag(p, 0, SEND_NODES_TAG) << ")"); Vector<Real> nodes_to_recv(nodes.storage() + nb_nodes * spatial_dimension, nb_nodes_to_recv(p) * spatial_dimension); comm.receive(nodes_to_recv, p, Tag::genTag(p, 0, SEND_NODES_TAG)); nb_nodes += nb_nodes_to_recv(p); } #if not defined(AKANTU_NDEBUG) else { if (p != my_rank) { AKANTU_DEBUG_INFO("No nodes to receive from processor " << p); } } #endif } comm.waitAll(isend_coordinates_requests); comm.freeCommunicationRequest(isend_coordinates_requests); mesh.sendEvent(new_nodes); mesh.sendEvent(new_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void GridSynchronizer::createGridSynchronizer<IntegrationPoint>( const SpatialGrid<IntegrationPoint> & grid); template void GridSynchronizer::createGridSynchronizer<Element>( const SpatialGrid<Element> & grid); } // namespace akantu diff --git a/src/synchronizer/grid_synchronizer.hh b/src/synchronizer/grid_synchronizer.hh index 1005d0654..62b0b039c 100644 --- a/src/synchronizer/grid_synchronizer.hh +++ b/src/synchronizer/grid_synchronizer.hh @@ -1,103 +1,102 @@ /** * @file grid_synchronizer.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 08 2015 + * @date last modification: Wed Nov 08 2017 * * @brief Synchronizer based on spatial grid * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_synchronizer.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GRID_SYNCHRONIZER_HH__ #define __AKANTU_GRID_SYNCHRONIZER_HH__ namespace akantu { class Mesh; template <class T> class SpatialGrid; class GridSynchronizer : public ElementSynchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: template <typename E> GridSynchronizer(Mesh & mesh, const SpatialGrid<E> & grid, const ID & id = "grid_synchronizer", MemoryID memory_id = 0, const bool register_to_event_manager = true, EventHandlerPriority event_priority = _ehp_synchronizer); template <typename E> GridSynchronizer(Mesh & mesh, const SpatialGrid<E> & grid, SynchronizerRegistry & synchronizer_registry, const std::set<SynchronizationTag> & tags_to_register, const ID & id = "grid_synchronizer", MemoryID memory_id = 0, const bool register_to_event_manager = true, EventHandlerPriority event_priority = _ehp_synchronizer); ~GridSynchronizer() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ private: /** *Create the Grid Synchronizer: *Compute intersection and send info to neighbours that will be stored in *ghosts elements */ template <typename E> void createGridSynchronizer(const SpatialGrid<E> & grid); protected: /// Define the tags that will be used in the send and receive instructions enum CommTags { SIZE_TAG = 0, DATA_TAG = 1, ASK_NODES_TAG = 2, SEND_NODES_TAG = 3 }; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; } // namespace akantu #include "grid_synchronizer_tmpl.hh" #endif /* __AKANTU_GRID_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/grid_synchronizer_tmpl.hh b/src/synchronizer/grid_synchronizer_tmpl.hh index fc33da1fe..32500b7f4 100644 --- a/src/synchronizer/grid_synchronizer_tmpl.hh +++ b/src/synchronizer/grid_synchronizer_tmpl.hh @@ -1,73 +1,75 @@ /** * @file grid_synchronizer_tmpl.hh * - * @author Nicolas Richart + * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date creation Tue Jun 20 2017 + * @date creation: Thu Jul 06 2017 + * @date last modification: Wed Aug 09 2017 * - * @brief A Documented file. + * @brief implementation of the templated part of the grid syncrhonizers * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "grid_synchronizer.hh" #ifndef __AKANTU_GRID_SYNCHRONIZER_TMPL_HH__ #define __AKANTU_GRID_SYNCHRONIZER_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename E> GridSynchronizer::GridSynchronizer(Mesh & mesh, const SpatialGrid<E> & grid, const ID & id, MemoryID memory_id, const bool register_to_event_manager, EventHandlerPriority event_priority) : ElementSynchronizer(mesh, id, memory_id, register_to_event_manager, event_priority) { AKANTU_DEBUG_IN(); this->createGridSynchronizer(grid); AKANTU_DEBUG_OUT(); } template <typename E> GridSynchronizer::GridSynchronizer( Mesh & mesh, const SpatialGrid<E> & grid, SynchronizerRegistry & synchronizer_registry, const std::set<SynchronizationTag> & tags_to_register, const ID & id, MemoryID memory_id, const bool register_to_event_manager, EventHandlerPriority event_priority) : GridSynchronizer(mesh, grid, id, memory_id, register_to_event_manager, event_priority) { AKANTU_DEBUG_IN(); // Register the tags if any for (auto & tag : tags_to_register) { synchronizer_registry.registerSynchronizer(*this, tag); } AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_GRID_SYNCHRONIZER_TMPL_HH__ */ diff --git a/src/synchronizer/master_element_info_per_processor.cc b/src/synchronizer/master_element_info_per_processor.cc index b3b91967a..74053d36e 100644 --- a/src/synchronizer/master_element_info_per_processor.cc +++ b/src/synchronizer/master_element_info_per_processor.cc @@ -1,461 +1,463 @@ /** * @file master_element_info_per_processor.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Mar 11 14:57:13 2016 + * @date creation: Wed Mar 16 2016 + * @date last modification: Tue Feb 20 2018 * - * @brief + * @brief Helper class to distribute a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "communicator.hh" #include "element_group.hh" #include "element_info_per_processor.hh" #include "element_synchronizer.hh" #include "mesh_iterators.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <iostream> #include <map> #include <tuple> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MasterElementInfoPerProc::MasterElementInfoPerProc( ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type, const MeshPartition & partition) : ElementInfoPerProc(synchronizer, message_cnt, root, type), partition(partition), all_nb_local_element(nb_proc, 0), all_nb_ghost_element(nb_proc, 0), all_nb_element_to_send(nb_proc, 0) { Vector<UInt> size(5); size(0) = (UInt)type; if (type != _not_defined) { nb_nodes_per_element = Mesh::getNbNodesPerElement(type); nb_element = mesh.getNbElement(type); const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); for (UInt el = 0; el < nb_element; ++el) { this->all_nb_local_element[partition_num(el)]++; for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { this->all_nb_ghost_element[*part]++; } this->all_nb_element_to_send[partition_num(el)] += ghost_partition.getNbCols(el) + 1; } /// tag info std::vector<std::string> tag_names; this->getMeshData().getTagNames(tag_names, type); this->nb_tags = tag_names.size(); size(4) = nb_tags; for (UInt p = 0; p < nb_proc; ++p) { if (p != root) { size(1) = this->all_nb_local_element[p]; size(2) = this->all_nb_ghost_element[p]; size(3) = this->all_nb_element_to_send[p]; AKANTU_DEBUG_INFO( "Sending connectivities informations to proc " << p << " TAG(" << Tag::genTag(this->rank, this->message_count, Tag::_SIZES) << ")"); comm.send(size, p, Tag::genTag(this->rank, this->message_count, Tag::_SIZES)); } else { this->nb_local_element = this->all_nb_local_element[p]; this->nb_ghost_element = this->all_nb_ghost_element[p]; } } } else { for (UInt p = 0; p < this->nb_proc; ++p) { if (p != this->root) { AKANTU_DEBUG_INFO( "Sending empty connectivities informations to proc " << p << " TAG(" << Tag::genTag(this->rank, this->message_count, Tag::_SIZES) << ")"); comm.send(size, p, Tag::genTag(this->rank, this->message_count, Tag::_SIZES)); } } } } /* ------------------------------------------------------------------------ */ void MasterElementInfoPerProc::synchronizeConnectivities() { const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); std::vector<Array<UInt>> buffers(this->nb_proc); const auto & connectivities = this->mesh.getConnectivity(this->type, _not_ghost); /// copying the local connectivity for (auto && part_conn : zip(partition_num, make_view(connectivities, this->nb_nodes_per_element))) { auto && part = std::get<0>(part_conn); auto && conn = std::get<1>(part_conn); for (UInt i = 0; i < conn.size(); ++i) { buffers[part].push_back(conn[i]); } } /// copying the connectivity of ghost element for (auto && tuple : enumerate(make_view(connectivities, this->nb_nodes_per_element))) { auto && el = std::get<0>(tuple); auto && conn = std::get<1>(tuple); for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { UInt proc = *part; for (UInt i = 0; i < conn.size(); ++i) { buffers[proc].push_back(conn[i]); } } } #ifndef AKANTU_NDEBUG for (auto p : arange(this->nb_proc)) { UInt size = this->nb_nodes_per_element * (this->all_nb_local_element[p] + this->all_nb_ghost_element[p]); AKANTU_DEBUG_ASSERT( buffers[p].size() == size, "The connectivity data packed in the buffer are not correct"); } #endif /// send all connectivity and ghost information to all processors std::vector<CommunicationRequest> requests; for (auto p : arange(this->nb_proc)) { if (p == this->root) continue; auto && tag = Tag::genTag(this->rank, this->message_count, Tag::_CONNECTIVITY); AKANTU_DEBUG_INFO("Sending connectivities to proc " << p << " TAG(" << tag << ")"); requests.push_back(comm.asyncSend(buffers[p], p, tag)); } Array<UInt> & old_nodes = this->getNodesGlobalIds(); /// create the renumbered connectivity AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, buffers[root], all_nb_local_element[root], all_nb_ghost_element[root], type, old_nodes); comm.waitAll(requests); comm.freeCommunicationRequest(requests); } /* ------------------------------------------------------------------------ */ void MasterElementInfoPerProc::synchronizePartitions() { const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); std::vector<Array<UInt>> buffers(this->partition.getNbPartition()); /// splitting the partition information to send them to processors Vector<UInt> count_by_proc(nb_proc, 0); for (UInt el = 0; el < nb_element; ++el) { UInt proc = partition_num(el); buffers[proc].push_back(ghost_partition.getNbCols(el)); UInt i(0); for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part, ++i) { buffers[proc].push_back(*part); } } for (UInt el = 0; el < nb_element; ++el) { UInt i(0); for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part, ++i) { buffers[*part].push_back(partition_num(el)); } } #ifndef AKANTU_NDEBUG for (UInt p = 0; p < this->nb_proc; ++p) { AKANTU_DEBUG_ASSERT(buffers[p].size() == (this->all_nb_ghost_element[p] + this->all_nb_element_to_send[p]), "Data stored in the buffer are most probably wrong"); } #endif std::vector<CommunicationRequest> requests; /// last data to compute the communication scheme for (UInt p = 0; p < this->nb_proc; ++p) { if (p == this->root) continue; auto && tag = Tag::genTag(this->rank, this->message_count, Tag::_PARTITIONS); AKANTU_DEBUG_INFO("Sending partition informations to proc " << p << " TAG(" << tag << ")"); requests.push_back(comm.asyncSend(buffers[p], p, tag)); } if (Mesh::getSpatialDimension(this->type) == this->mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); this->fillCommunicationScheme(buffers[this->rank]); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); } /* -------------------------------------------------------------------------- */ void MasterElementInfoPerProc::synchronizeTags() { AKANTU_DEBUG_IN(); if (this->nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } UInt mesh_data_sizes_buffer_length; auto & mesh_data = this->getMeshData(); /// tag info std::vector<std::string> tag_names; mesh_data.getTagNames(tag_names, type); // Make sure the tags are sorted (or at least not in random order), // because they come from a map !! std::sort(tag_names.begin(), tag_names.end()); // Sending information about the tags in mesh_data: name, data type and // number of components of the underlying array associated to the current // type DynamicCommunicationBuffer mesh_data_sizes_buffer; for (auto && tag_name : tag_names) { mesh_data_sizes_buffer << tag_name; mesh_data_sizes_buffer << mesh_data.getTypeCode(tag_name); mesh_data_sizes_buffer << mesh_data.getNbComponent(tag_name, type); } mesh_data_sizes_buffer_length = mesh_data_sizes_buffer.size(); AKANTU_DEBUG_INFO( "Broadcasting the size of the information about the mesh data tags: (" << mesh_data_sizes_buffer_length << ")."); comm.broadcast(mesh_data_sizes_buffer_length, root); AKANTU_DEBUG_INFO( "Broadcasting the information about the mesh data tags, addr " << (void *)mesh_data_sizes_buffer.storage()); if (mesh_data_sizes_buffer_length != 0) comm.broadcast(mesh_data_sizes_buffer, root); if (mesh_data_sizes_buffer_length != 0) { // Sending the actual data to each processor std::vector<DynamicCommunicationBuffer> buffers(nb_proc); // Loop over each tag for the current type for (auto && tag_name : tag_names) { // Type code of the current tag (i.e. the tag named *names_it) this->fillTagBuffer(buffers, tag_name); } std::vector<CommunicationRequest> requests; for (UInt p = 0; p < nb_proc; ++p) { if (p == root) continue; auto && tag = Tag::genTag(this->rank, this->message_count, Tag::_MESH_DATA); AKANTU_DEBUG_INFO("Sending " << buffers[p].size() << " bytes of mesh data to proc " << p << " TAG(" << tag << ")"); requests.push_back(comm.asyncSend(buffers[p], p, tag)); } // Loop over each tag for the current type for (auto && tag_name : tag_names) { // Reinitializing the mesh data on the master this->fillMeshData(buffers[root], tag_name, mesh_data.getTypeCode(tag_name), mesh_data.getNbComponent(tag_name, type)); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void MasterElementInfoPerProc::fillTagBufferTemplated( std::vector<DynamicCommunicationBuffer> & buffers, const std::string & tag_name) { MeshData & mesh_data = this->getMeshData(); const auto & data = mesh_data.getElementalDataArray<T>(tag_name, type); const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); // Not possible to use the iterator because it potentially triggers the // creation of complex // type templates (such as akantu::Vector< std::vector<Element> > which don't // implement the right interface // (e.g. operator<< in that case). // typename Array<T>::template const_iterator< Vector<T> > data_it = // data.begin(data.getNbComponent()); // typename Array<T>::template const_iterator< Vector<T> > data_end = // data.end(data.getNbComponent()); const T * data_it = data.storage(); const T * data_end = data.storage() + data.size() * data.getNbComponent(); const UInt * part = partition_num.storage(); /// copying the data, element by element for (; data_it != data_end; ++part) { for (UInt j(0); j < data.getNbComponent(); ++j, ++data_it) { buffers[*part] << *data_it; } } data_it = data.storage(); /// copying the data for the ghost element for (UInt el(0); data_it != data_end; data_it += data.getNbComponent(), ++el) { auto it = ghost_partition.begin(el); auto end = ghost_partition.end(el); for (; it != end; ++it) { UInt proc = *it; for (UInt j(0); j < data.getNbComponent(); ++j) { buffers[proc] << data_it[j]; } } } } /* -------------------------------------------------------------------------- */ void MasterElementInfoPerProc::fillTagBuffer( std::vector<DynamicCommunicationBuffer> & buffers, const std::string & tag_name) { MeshData & mesh_data = this->getMeshData(); #define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ this->fillTagBufferTemplated<BOOST_PP_TUPLE_ELEM(2, 1, elem)>(buffers, \ tag_name); \ break; \ } MeshDataTypeCode data_type_code = mesh_data.getTypeCode(tag_name); switch (data_type_code) { BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , AKANTU_MESH_DATA_TYPES) default: AKANTU_ERROR("Could not obtain the type of tag" << tag_name << "!"); break; } #undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA } /* -------------------------------------------------------------------------- */ void MasterElementInfoPerProc::synchronizeGroups() { AKANTU_DEBUG_IN(); std::vector<DynamicCommunicationBuffer> buffers(nb_proc); using ElementToGroup = std::vector<std::vector<std::string>>; ElementToGroup element_to_group(nb_element); for (auto & eg : ElementGroupsIterable(mesh)) { const auto & name = eg.getName(); for (const auto & element : eg.getElements(type, _not_ghost)) { element_to_group[element].push_back(name); } auto eit = eg.begin(type, _not_ghost); if (eit != eg.end(type, _not_ghost)) const_cast<Array<UInt> &>(eg.getElements(type)).empty(); } const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); /// copying the data, element by element for (auto && pair : zip(partition_num, element_to_group)) { buffers[std::get<0>(pair)] << std::get<1>(pair); } /// copying the data for the ghost element for (auto && pair : enumerate(element_to_group)) { auto && el = std::get<0>(pair); auto it = ghost_partition.begin(el); auto end = ghost_partition.end(el); for (; it != end; ++it) { UInt proc = *it; buffers[proc] << std::get<1>(pair); } } std::vector<CommunicationRequest> requests; for (UInt p = 0; p < this->nb_proc; ++p) { if (p == this->rank) continue; auto && tag = Tag::genTag(this->rank, p, Tag::_ELEMENT_GROUP); AKANTU_DEBUG_INFO("Sending element groups to proc " << p << " TAG(" << tag << ")"); requests.push_back(comm.asyncSend(buffers[p], p, tag)); } this->fillElementGroupsFromBuffer(buffers[this->rank]); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/mpi_communicator_data.hh b/src/synchronizer/mpi_communicator_data.hh index be387e22b..f85d30c8b 100644 --- a/src/synchronizer/mpi_communicator_data.hh +++ b/src/synchronizer/mpi_communicator_data.hh @@ -1,135 +1,134 @@ /** - * @file mpi_type_wrapper.hh + * @file mpi_communicator_data.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 - * @date last modification: Wed Oct 07 2015 + * @date last modification: Mon Feb 05 2018 * * @brief Wrapper on MPI types to have a better separation between libraries * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it // is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #if __cplusplus > 199711L #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wliteral-suffix" #endif #endif #include <mpi.h> #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it // is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #if __cplusplus > 199711L #pragma GCC diagnostic pop #endif #endif /* -------------------------------------------------------------------------- */ #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <unordered_map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MPI_TYPE_WRAPPER_HH__ #define __AKANTU_MPI_TYPE_WRAPPER_HH__ namespace akantu { class MPICommunicatorData : public CommunicatorInternalData { public: MPICommunicatorData() { MPI_Initialized(&is_externaly_initialized); if (!is_externaly_initialized) { MPI_Init(nullptr, nullptr); // valid according to the spec } MPI_Comm_create_errhandler(MPICommunicatorData::errorHandler, &error_handler); MPI_Comm_set_errhandler(MPI_COMM_WORLD, error_handler); setMPICommunicator(MPI_COMM_WORLD); } ~MPICommunicatorData() override { if (not is_externaly_initialized) { MPI_Finalize(); } } inline void setMPICommunicator(MPI_Comm comm) { MPI_Comm_set_errhandler(communicator, save_error_handler); communicator = comm; MPI_Comm_get_errhandler(comm, &save_error_handler); MPI_Comm_set_errhandler(comm, error_handler); } inline int rank() const { int prank; MPI_Comm_rank(communicator, &prank); return prank; } inline int size() const { int psize; MPI_Comm_size(communicator, &psize); return psize; } inline MPI_Comm getMPICommunicator() const { return communicator; } inline int getMaxTag() const { int flag; int * value; MPI_Comm_get_attr(communicator, MPI_TAG_UB, &value, &flag); AKANTU_DEBUG_ASSERT(flag, "No attribute MPI_TAG_UB."); return *value; } private: MPI_Comm communicator{MPI_COMM_WORLD}; MPI_Errhandler save_error_handler{MPI_ERRORS_ARE_FATAL}; static int is_externaly_initialized; /* ------------------------------------------------------------------------ */ MPI_Errhandler error_handler; static void errorHandler(MPI_Comm * /*comm*/, int * error_code, ...) { char error_string[MPI_MAX_ERROR_STRING]; int str_len; MPI_Error_string(*error_code, error_string, &str_len); AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), "MPI failed with the error code " << *error_code << ": \"" << error_string << "\""); } }; } // namespace akantu #endif /* __AKANTU_MPI_TYPE_WRAPPER_HH__ */ diff --git a/src/synchronizer/node_info_per_processor.cc b/src/synchronizer/node_info_per_processor.cc index 3b4a73b32..bed5332f1 100644 --- a/src/synchronizer/node_info_per_processor.cc +++ b/src/synchronizer/node_info_per_processor.cc @@ -1,497 +1,499 @@ /** * @file node_info_per_processor.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Mar 11 15:49:43 2016 + * @date creation: Wed Mar 16 2016 + * @date last modification: Wed Nov 08 2017 * - * @brief + * @brief Please type the brief for file: Helper classes to create the + * distributed synchronizer and distribute a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "node_info_per_processor.hh" #include "communicator.hh" #include "node_group.hh" #include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NodeInfoPerProc::NodeInfoPerProc(NodeSynchronizer & synchronizer, UInt message_cnt, UInt root) : MeshAccessor(synchronizer.getMesh()), synchronizer(synchronizer), comm(synchronizer.getCommunicator()), rank(comm.whoAmI()), nb_proc(comm.getNbProc()), root(root), mesh(synchronizer.getMesh()), spatial_dimension(synchronizer.getMesh().getSpatialDimension()), message_count(message_cnt) {} /* -------------------------------------------------------------------------- */ template <class CommunicationBuffer> void NodeInfoPerProc::fillNodeGroupsFromBuffer(CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); std::vector<std::vector<std::string>> node_to_group; buffer >> node_to_group; AKANTU_DEBUG_ASSERT(node_to_group.size() == mesh.getNbGlobalNodes(), "Not the good amount of nodes where transmitted"); const auto & global_nodes = mesh.getGlobalNodesIds(); auto nbegin = global_nodes.begin(); auto nit = global_nodes.begin(); auto nend = global_nodes.end(); for (; nit != nend; ++nit) { auto it = node_to_group[*nit].begin(); auto end = node_to_group[*nit].end(); for (; it != end; ++it) { mesh.getNodeGroup(*it).add(nit - nbegin, false); } } GroupManager::const_node_group_iterator ngi = mesh.node_group_begin(); GroupManager::const_node_group_iterator nge = mesh.node_group_end(); for (; ngi != nge; ++ngi) { NodeGroup & ng = *(ngi->second); ng.optimize(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NodeInfoPerProc::fillNodesType() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); Array<NodeType> & nodes_type = this->getNodesType(); Array<UInt> nodes_set(nb_nodes); nodes_set.set(0); enum NodeSet { NORMAL_SET = 1, GHOST_SET = 2, }; Array<bool> already_seen(nb_nodes, 1, false); for (UInt g = _not_ghost; g <= _ghost; ++g) { auto gt = (GhostType)g; UInt set = NORMAL_SET; if (gt == _ghost) set = GHOST_SET; already_seen.set(false); Mesh::type_iterator it = mesh.firstType(_all_dimensions, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, gt, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type, gt); Array<UInt>::const_vector_iterator conn_it = mesh.getConnectivity(type, gt).begin(nb_nodes_per_element); for (UInt e = 0; e < nb_element; ++e, ++conn_it) { const Vector<UInt> & conn = *conn_it; for (UInt n = 0; n < nb_nodes_per_element; ++n) { AKANTU_DEBUG_ASSERT(conn(n) < nb_nodes, "Node " << conn(n) << " bigger than number of nodes " << nb_nodes); if (!already_seen(conn(n))) { nodes_set(conn(n)) += set; already_seen(conn(n)) = true; } } } } } for (UInt i = 0; i < nb_nodes; ++i) { if (nodes_set(i) == NORMAL_SET) nodes_type(i) = _nt_normal; else if (nodes_set(i) == GHOST_SET) nodes_type(i) = _nt_pure_gost; else if (nodes_set(i) == (GHOST_SET + NORMAL_SET)) nodes_type(i) = _nt_master; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NodeInfoPerProc::fillCommunicationScheme(const Array<UInt> & master_info) { AKANTU_DEBUG_IN(); Communications<UInt> & communications = this->synchronizer.getCommunications(); { // send schemes auto it = master_info.begin_reinterpret(2, master_info.size() / 2); auto end = master_info.end_reinterpret(2, master_info.size() / 2); std::map<UInt, Array<UInt>> send_array_per_proc; for (; it != end; ++it) { const Vector<UInt> & send_info = *it; send_array_per_proc[send_info(0)].push_back(send_info(1)); } for (auto & send_schemes : send_array_per_proc) { auto & scheme = communications.createSendScheme(send_schemes.first); auto & sends = send_schemes.second; std::sort(sends.begin(), sends.end()); std::transform(sends.begin(), sends.end(), sends.begin(), [this](UInt g) -> UInt { return mesh.getNodeLocalId(g); }); scheme.copy(sends); } } { // receive schemes const Array<NodeType> & nodes_type = this->getNodesType(); std::map<UInt, Array<UInt>> recv_array_per_proc; UInt node = 0; for (auto & node_type : nodes_type) { if (Int(node_type) >= 0) { recv_array_per_proc[node_type].push_back(mesh.getNodeGlobalId(node)); } ++node; } for (auto & recv_schemes : recv_array_per_proc) { auto & scheme = communications.createRecvScheme(recv_schemes.first); auto & recvs = recv_schemes.second; std::sort(recvs.begin(), recvs.end()); std::transform(recvs.begin(), recvs.end(), recvs.begin(), [this](UInt g) -> UInt { return mesh.getNodeLocalId(g); }); scheme.copy(recvs); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ MasterNodeInfoPerProc::MasterNodeInfoPerProc(NodeSynchronizer & synchronizer, UInt message_cnt, UInt root) : NodeInfoPerProc(synchronizer, message_cnt, root) { UInt nb_global_nodes = this->mesh.getNbGlobalNodes(); this->comm.broadcast(nb_global_nodes, this->root); } /* -------------------------------------------------------------------------- */ void MasterNodeInfoPerProc::synchronizeNodes() { this->nodes_per_proc.resize(nb_proc); this->nb_nodes_per_proc.resize(nb_proc); Array<Real> local_nodes(0, spatial_dimension); Array<Real> & nodes = this->getNodes(); for (UInt p = 0; p < nb_proc; ++p) { UInt nb_nodes = 0; // UInt * buffer; Array<Real> * nodes_to_send; Array<UInt> & nodespp = nodes_per_proc[p]; if (p != root) { nodes_to_send = new Array<Real>(0, spatial_dimension); AKANTU_DEBUG_INFO("Receiving number of nodes from proc " << p << " " << Tag::genTag(p, 0, Tag::_NB_NODES)); comm.receive(nb_nodes, p, Tag::genTag(p, 0, Tag::_NB_NODES)); nodespp.resize(nb_nodes); this->nb_nodes_per_proc(p) = nb_nodes; AKANTU_DEBUG_INFO("Receiving list of nodes from proc " << p << " " << Tag::genTag(p, 0, Tag::_NODES)); comm.receive(nodespp, p, Tag::genTag(p, 0, Tag::_NODES)); } else { Array<UInt> & local_ids = this->getNodesGlobalIds(); this->nb_nodes_per_proc(p) = local_ids.size(); nodespp.copy(local_ids); nodes_to_send = &local_nodes; } Array<UInt>::const_scalar_iterator it = nodespp.begin(); Array<UInt>::const_scalar_iterator end = nodespp.end(); /// get the coordinates for the selected nodes for (; it != end; ++it) { Vector<Real> coord(nodes.storage() + spatial_dimension * *it, spatial_dimension); nodes_to_send->push_back(coord); } if (p != root) { /// send them for distant processors AKANTU_DEBUG_INFO("Sending coordinates to proc " << p << " " << Tag::genTag(this->rank, 0, Tag::_COORDINATES)); comm.send(*nodes_to_send, p, Tag::genTag(this->rank, 0, Tag::_COORDINATES)); delete nodes_to_send; } } /// construct the local nodes coordinates nodes.copy(local_nodes); } /* -------------------------------------------------------------------------- */ void MasterNodeInfoPerProc::synchronizeTypes() { // <global_id, <proc, local_id> > std::multimap<UInt, std::pair<UInt, UInt>> nodes_to_proc; std::vector<Array<NodeType>> nodes_type_per_proc(nb_proc); // arrays containing pairs of (proc, node) std::vector<Array<UInt>> nodes_to_send_per_proc(nb_proc); for (UInt p = 0; p < nb_proc; ++p) { nodes_type_per_proc[p].resize(nb_nodes_per_proc(p)); } this->fillNodesType(); for (UInt p = 0; p < nb_proc; ++p) { auto & nodes_types = nodes_type_per_proc[p]; if (p != root) { AKANTU_DEBUG_INFO( "Receiving first nodes types from proc " << p << " " << Tag::genTag(this->rank, this->message_count, Tag::_NODES_TYPE)); comm.receive(nodes_types, p, Tag::genTag(p, 0, Tag::_NODES_TYPE)); } else { nodes_types.copy(this->getNodesType()); } // stack all processors claiming to be master for a node for (UInt local_node = 0; local_node < nb_nodes_per_proc(p); ++local_node) { if (nodes_types(local_node) == _nt_master) { UInt global_node = nodes_per_proc[p](local_node); nodes_to_proc.insert( std::make_pair(global_node, std::make_pair(p, local_node))); } } } for (UInt i = 0; i < mesh.getNbGlobalNodes(); ++i) { auto it_range = nodes_to_proc.equal_range(i); if (it_range.first == nodes_to_proc.end() || it_range.first->first != i) continue; // pick the first processor out of the multi-map as the actual master UInt master_proc = (it_range.first)->second.first; for (auto it_node = it_range.first; it_node != it_range.second; ++it_node) { UInt proc = it_node->second.first; UInt node = it_node->second.second; if (proc != master_proc) { // store the info on all the slaves for a given master nodes_type_per_proc[proc](node) = NodeType(master_proc); nodes_to_send_per_proc[master_proc].push_back(proc); nodes_to_send_per_proc[master_proc].push_back(i); } } } std::vector<CommunicationRequest> requests_send_type; std::vector<CommunicationRequest> requests_send_master_info; for (UInt p = 0; p < nb_proc; ++p) { if (p != root) { AKANTU_DEBUG_INFO("Sending nodes types to proc " << p << " " << Tag::genTag(this->rank, 0, Tag::_NODES_TYPE)); requests_send_type.push_back( comm.asyncSend(nodes_type_per_proc[p], p, Tag::genTag(this->rank, 0, Tag::_NODES_TYPE))); auto & nodes_to_send = nodes_to_send_per_proc[p]; /// push back an element to avoid a send of size 0 nodes_to_send.push_back(-1); AKANTU_DEBUG_INFO("Sending nodes master info to proc " << p << " " << Tag::genTag(this->rank, 1, Tag::_NODES_TYPE)); requests_send_master_info.push_back(comm.asyncSend( nodes_to_send, p, Tag::genTag(this->rank, 1, Tag::_NODES_TYPE))); } else { this->getNodesType().copy(nodes_type_per_proc[p]); this->fillCommunicationScheme(nodes_to_send_per_proc[root]); } } comm.waitAll(requests_send_type); comm.freeCommunicationRequest(requests_send_type); requests_send_type.clear(); comm.waitAll(requests_send_master_info); comm.freeCommunicationRequest(requests_send_master_info); } /* -------------------------------------------------------------------------- */ void MasterNodeInfoPerProc::synchronizeGroups() { AKANTU_DEBUG_IN(); UInt nb_total_nodes = mesh.getNbGlobalNodes(); DynamicCommunicationBuffer buffer; using NodeToGroup = std::vector<std::vector<std::string>>; NodeToGroup node_to_group; node_to_group.resize(nb_total_nodes); GroupManager::const_node_group_iterator ngi = mesh.node_group_begin(); GroupManager::const_node_group_iterator nge = mesh.node_group_end(); for (; ngi != nge; ++ngi) { NodeGroup & ng = *(ngi->second); std::string name = ngi->first; NodeGroup::const_node_iterator nit = ng.begin(); NodeGroup::const_node_iterator nend = ng.end(); for (; nit != nend; ++nit) { node_to_group[*nit].push_back(name); } nit = ng.begin(); if (nit != nend) ng.empty(); } buffer << node_to_group; std::vector<CommunicationRequest> requests; for (UInt p = 0; p < nb_proc; ++p) { if (p == this->rank) continue; AKANTU_DEBUG_INFO("Sending node groups to proc " << p << " " << Tag::genTag(this->rank, p, Tag::_NODE_GROUP)); requests.push_back(comm.asyncSend( buffer, p, Tag::genTag(this->rank, p, Tag::_NODE_GROUP))); } this->fillNodeGroupsFromBuffer(buffer); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ SlaveNodeInfoPerProc::SlaveNodeInfoPerProc(NodeSynchronizer & synchronizer, UInt message_cnt, UInt root) : NodeInfoPerProc(synchronizer, message_cnt, root) { UInt nb_global_nodes = 0; comm.broadcast(nb_global_nodes, root); this->setNbGlobalNodes(nb_global_nodes); } /* -------------------------------------------------------------------------- */ void SlaveNodeInfoPerProc::synchronizeNodes() { AKANTU_DEBUG_INFO("Sending list of nodes to proc " << root << " " << Tag::genTag(this->rank, 0, Tag::_NB_NODES) << " " << Tag::genTag(this->rank, 0, Tag::_NODES)); Array<UInt> & local_ids = this->getNodesGlobalIds(); Array<Real> & nodes = this->getNodes(); UInt nb_nodes = local_ids.size(); comm.send(nb_nodes, root, Tag::genTag(this->rank, 0, Tag::_NB_NODES)); comm.send(local_ids, root, Tag::genTag(this->rank, 0, Tag::_NODES)); /* --------<<<<-COORDINATES---------------------------------------------- */ nodes.resize(nb_nodes); AKANTU_DEBUG_INFO("Receiving coordinates from proc " << root << " " << Tag::genTag(root, 0, Tag::_COORDINATES)); comm.receive(nodes, root, Tag::genTag(root, 0, Tag::_COORDINATES)); } /* -------------------------------------------------------------------------- */ void SlaveNodeInfoPerProc::synchronizeTypes() { this->fillNodesType(); Array<NodeType> & nodes_types = this->getNodesType(); AKANTU_DEBUG_INFO("Sending first nodes types to proc " << root << "" << Tag::genTag(this->rank, 0, Tag::_NODES_TYPE)); comm.send(nodes_types, root, Tag::genTag(this->rank, 0, Tag::_NODES_TYPE)); AKANTU_DEBUG_INFO("Receiving nodes types from proc " << root << " " << Tag::genTag(root, 0, Tag::_NODES_TYPE)); comm.receive(nodes_types, root, Tag::genTag(root, 0, Tag::_NODES_TYPE)); AKANTU_DEBUG_INFO("Receiving nodes master info from proc " << root << " " << Tag::genTag(root, 1, Tag::_NODES_TYPE)); CommunicationStatus status; comm.probe<UInt>(root, Tag::genTag(root, 1, Tag::_NODES_TYPE), status); Array<UInt> nodes_master_info(status.size()); comm.receive(nodes_master_info, root, Tag::genTag(root, 1, Tag::_NODES_TYPE)); nodes_master_info.resize(nodes_master_info.size() - 1); this->fillCommunicationScheme(nodes_master_info); } /* -------------------------------------------------------------------------- */ void SlaveNodeInfoPerProc::synchronizeGroups() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Receiving node groups from proc " << root << " " << Tag::genTag(root, this->rank, Tag::_NODE_GROUP)); CommunicationStatus status; comm.probe<char>(root, Tag::genTag(root, this->rank, Tag::_NODE_GROUP), status); CommunicationBuffer buffer(status.size()); comm.receive(buffer, root, Tag::genTag(root, this->rank, Tag::_NODE_GROUP)); this->fillNodeGroupsFromBuffer(buffer); AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/synchronizer/node_info_per_processor.hh b/src/synchronizer/node_info_per_processor.hh index da67e5479..1bb583524 100644 --- a/src/synchronizer/node_info_per_processor.hh +++ b/src/synchronizer/node_info_per_processor.hh @@ -1,107 +1,108 @@ /** * @file node_info_per_processor.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Mar 11 14:45:15 2016 + * @date creation: Wed Mar 16 2016 + * @date last modification: Wed Nov 08 2017 * * @brief Helper classes to create the distributed synchronizer and distribute - * a mesh + * a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NODE_INFO_PER_PROCESSOR_HH__ #define __AKANTU_NODE_INFO_PER_PROCESSOR_HH__ namespace akantu { class NodeSynchronizer; class Communicator; } /* -------------------------------------------------------------------------- */ namespace akantu { class NodeInfoPerProc : protected MeshAccessor { public: NodeInfoPerProc(NodeSynchronizer & synchronizer, UInt message_cnt, UInt root); virtual void synchronizeNodes() = 0; virtual void synchronizeTypes() = 0; virtual void synchronizeGroups() = 0; protected: template <class CommunicationBuffer> void fillNodeGroupsFromBuffer(CommunicationBuffer & buffer); void fillNodesType(); void fillCommunicationScheme(const Array<UInt> &); protected: NodeSynchronizer & synchronizer; const Communicator & comm; UInt rank; UInt nb_proc; UInt root; Mesh & mesh; UInt spatial_dimension; UInt message_count; }; /* -------------------------------------------------------------------------- */ class MasterNodeInfoPerProc : protected NodeInfoPerProc { public: MasterNodeInfoPerProc(NodeSynchronizer & synchronizer, UInt message_cnt, UInt root); void synchronizeNodes() override; void synchronizeTypes() override; void synchronizeGroups() override; private: /// get the list of nodes to send and send them std::vector<Array<UInt>> nodes_per_proc; Array<UInt> nb_nodes_per_proc; }; /* -------------------------------------------------------------------------- */ class SlaveNodeInfoPerProc : protected NodeInfoPerProc { public: SlaveNodeInfoPerProc(NodeSynchronizer & synchronizer, UInt message_cnt, UInt root); void synchronizeNodes() override; void synchronizeTypes() override; void synchronizeGroups() override; private: }; } // akantu #endif /* __AKANTU_NODE_INFO_PER_PROCESSOR_HH__ */ diff --git a/src/synchronizer/node_synchronizer.cc b/src/synchronizer/node_synchronizer.cc index 7610c7a3a..15c889ffb 100644 --- a/src/synchronizer/node_synchronizer.cc +++ b/src/synchronizer/node_synchronizer.cc @@ -1,121 +1,122 @@ /** * @file node_synchronizer.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Sep 23 12:01:24 2016 + * @date creation: Fri Jun 18 2010 + * @date last modification: Wed Nov 15 2017 * * @brief Implementation of the node synchronizer * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "node_synchronizer.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NodeSynchronizer::NodeSynchronizer(Mesh & mesh, const ID & id, MemoryID memory_id, const bool register_to_event_manager, EventHandlerPriority event_priority) : SynchronizerImpl<UInt>(mesh.getCommunicator(), id, memory_id), mesh(mesh) { AKANTU_DEBUG_IN(); if (register_to_event_manager) { this->mesh.registerEventHandler(*this, event_priority); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NodeSynchronizer::~NodeSynchronizer() = default; /* -------------------------------------------------------------------------- */ void NodeSynchronizer::onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent &) { std::map<UInt, std::vector<UInt>> nodes_per_proc; Array<UInt> sizes_per_proc(nb_proc, nb_proc, UInt(0)); Vector<UInt> local_sizes_per_proc = sizes_per_proc.begin(nb_proc)[rank]; for (auto & local_id : nodes_list) { auto type = mesh.getNodeType(local_id); if (type < 0) continue; // local, master or pure ghost auto global_id = mesh.getNodeGlobalId(local_id); auto proc = UInt(type); nodes_per_proc[proc].push_back(global_id); ++local_sizes_per_proc[proc]; auto & scheme = communications.getScheme(proc, _recv); scheme.push_back(local_id); } communicator.allGather(sizes_per_proc); std::vector<CommunicationRequest> send_request_per_proc, recv_request_per_proc; std::map<UInt, std::vector<UInt>> nodes_needed_by_proc; for (UInt proc = 0; proc < nb_proc; ++proc) { auto size = sizes_per_proc(proc, rank); if (size == 0) continue; nodes_needed_by_proc[proc].resize(size); recv_request_per_proc.push_back(communicator.asyncReceive( nodes_needed_by_proc[proc], proc, Tag::genTag(rank, 0, 0))); } for (auto & pair : nodes_per_proc) { auto proc = pair.first; auto & nodes = pair.second; send_request_per_proc.push_back( communicator.asyncSend(nodes, proc, Tag::genTag(proc, 0, 0))); } UInt req_nb; while ((req_nb = communicator.waitAny(recv_request_per_proc)) != UInt(-1)) { auto & request = recv_request_per_proc[req_nb]; auto proc = request.getSource(); auto & nodes = nodes_needed_by_proc[proc]; auto & scheme = communications.getScheme(proc, _send); for (auto global_id : nodes) { auto local_id = mesh.getNodeLocalId(global_id); AKANTU_DEBUG_ASSERT(local_id != UInt(-1), "The global node " << global_id << "is not known on rank " << rank); scheme.push_back(local_id); } recv_request_per_proc.erase(recv_request_per_proc.begin() + req_nb); } communicator.waitAll(send_request_per_proc); communicator.freeCommunicationRequest(send_request_per_proc); } } // namespace akantu diff --git a/src/synchronizer/node_synchronizer.hh b/src/synchronizer/node_synchronizer.hh index cc600ca2b..5378ef648 100644 --- a/src/synchronizer/node_synchronizer.hh +++ b/src/synchronizer/node_synchronizer.hh @@ -1,86 +1,87 @@ /** * @file node_synchronizer.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Sep 23 11:45:24 2016 + * @date creation: Tue Nov 08 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Synchronizer for nodal information * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_events.hh" #include "synchronizer_impl.hh" /* -------------------------------------------------------------------------- */ #include <unordered_map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NODE_SYNCHRONIZER_HH__ #define __AKANTU_NODE_SYNCHRONIZER_HH__ namespace akantu { class NodeSynchronizer : public MeshEventHandler, public SynchronizerImpl<UInt> { public: NodeSynchronizer(Mesh & mesh, const ID & id = "element_synchronizer", MemoryID memory_id = 0, const bool register_to_event_manager = true, EventHandlerPriority event_priority = _ehp_synchronizer); ~NodeSynchronizer() override; friend class NodeInfoPerProc; /// function to implement to react on akantu::NewNodesEvent void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) override; /// function to implement to react on akantu::RemovedNodesEvent void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, const RemovedNodesEvent &) override {} /// function to implement to react on akantu::NewElementsEvent void onElementsAdded(const Array<Element> &, const NewElementsEvent &) override {} /// function to implement to react on akantu::RemovedElementsEvent void onElementsRemoved(const Array<Element> &, const ElementTypeMapArray<UInt> &, const RemovedElementsEvent &) override {} /// function to implement to react on akantu::ChangedElementsEvent void onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) override {} public: AKANTU_GET_MACRO(Mesh, mesh, Mesh &); protected: Int getRank(const UInt & /*node*/) const final { AKANTU_TO_IMPLEMENT(); } protected: Mesh & mesh; // std::unordered_map<UInt, Int> node_to_prank; }; } // namespace akantu #endif /* __AKANTU_NODE_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/slave_element_info_per_processor.cc b/src/synchronizer/slave_element_info_per_processor.cc index 0d9415e1a..e38400012 100644 --- a/src/synchronizer/slave_element_info_per_processor.cc +++ b/src/synchronizer/slave_element_info_per_processor.cc @@ -1,197 +1,198 @@ /** * @file slave_element_info_per_processor.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Fri Mar 11 14:59:21 2016 + * @date creation: Wed Mar 16 2016 + * @date last modification: Tue Nov 07 2017 * - * @brief + * @brief Helper class to distribute a mesh * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "element_info_per_processor.hh" #include "element_synchronizer.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <iostream> #include <map> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SlaveElementInfoPerProc::SlaveElementInfoPerProc( ElementSynchronizer & synchronizer, UInt message_cnt, UInt root) : ElementInfoPerProc(synchronizer, message_cnt, root, _not_defined) { Vector<UInt> size(5); comm.receive(size, this->root, Tag::genTag(this->root, this->message_count, Tag::_SIZES)); this->type = (ElementType)size[0]; this->nb_local_element = size[1]; this->nb_ghost_element = size[2]; this->nb_element_to_receive = size[3]; this->nb_tags = size[4]; if (this->type != _not_defined) this->nb_nodes_per_element = Mesh::getNbNodesPerElement(type); } /* -------------------------------------------------------------------------- */ bool SlaveElementInfoPerProc::needSynchronize() { return this->type != _not_defined; } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizeConnectivities() { Array<UInt> local_connectivity( (this->nb_local_element + this->nb_ghost_element) * this->nb_nodes_per_element); AKANTU_DEBUG_INFO("Receiving connectivities from proc " << root); comm.receive( local_connectivity, this->root, Tag::genTag(this->root, this->message_count, Tag::_CONNECTIVITY)); auto & old_nodes = this->getNodesGlobalIds(); AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(this->mesh, local_connectivity, this->nb_local_element, this->nb_ghost_element, this->type, old_nodes); } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizePartitions() { Array<UInt> local_partitions(this->nb_element_to_receive + this->nb_ghost_element * 2); AKANTU_DEBUG_INFO("Receiving partition informations from proc " << root); this->comm.receive(local_partitions, this->root, Tag::genTag(root, this->message_count, Tag::_PARTITIONS)); if (Mesh::getSpatialDimension(this->type) == this->mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); this->fillCommunicationScheme(local_partitions); } } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizeTags() { AKANTU_DEBUG_IN(); if (this->nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } /* --------<<<<-TAGS------------------------------------------------- */ UInt mesh_data_sizes_buffer_length = 0; CommunicationBuffer mesh_data_sizes_buffer; AKANTU_DEBUG_INFO( "Receiving the size of the information about the mesh data tags."); comm.broadcast(mesh_data_sizes_buffer_length, root); if (mesh_data_sizes_buffer_length != 0) { mesh_data_sizes_buffer.resize(mesh_data_sizes_buffer_length); AKANTU_DEBUG_INFO( "Receiving the information about the mesh data tags, addr " << (void *)mesh_data_sizes_buffer.storage()); comm.broadcast(mesh_data_sizes_buffer, root); AKANTU_DEBUG_INFO("Size of the information about the mesh data: " << mesh_data_sizes_buffer_length); std::vector<std::string> tag_names; std::vector<MeshDataTypeCode> tag_type_codes; std::vector<UInt> tag_nb_component; tag_names.resize(nb_tags); tag_type_codes.resize(nb_tags); tag_nb_component.resize(nb_tags); CommunicationBuffer mesh_data_buffer; UInt type_code_int; for (UInt i(0); i < nb_tags; ++i) { mesh_data_sizes_buffer >> tag_names[i]; mesh_data_sizes_buffer >> type_code_int; tag_type_codes[i] = static_cast<MeshDataTypeCode>(type_code_int); mesh_data_sizes_buffer >> tag_nb_component[i]; } std::vector<std::string>::const_iterator names_it = tag_names.begin(); std::vector<std::string>::const_iterator names_end = tag_names.end(); CommunicationStatus mesh_data_comm_status; AKANTU_DEBUG_INFO("Checking size of data to receive for mesh data TAG(" << Tag::genTag(root, this->message_count, Tag::_MESH_DATA) << ")"); comm.probe<char>(root, Tag::genTag(root, this->message_count, Tag::_MESH_DATA), mesh_data_comm_status); UInt mesh_data_buffer_size(mesh_data_comm_status.size()); AKANTU_DEBUG_INFO("Receiving " << mesh_data_buffer_size << " bytes of mesh data TAG(" << Tag::genTag(root, this->message_count, Tag::_MESH_DATA) << ")"); mesh_data_buffer.resize(mesh_data_buffer_size); comm.receive(mesh_data_buffer, root, Tag::genTag(root, this->message_count, Tag::_MESH_DATA)); // Loop over each tag for the current type UInt k(0); for (; names_it != names_end; ++names_it, ++k) { this->fillMeshData(mesh_data_buffer, *names_it, tag_type_codes[k], tag_nb_component[k]); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizeGroups() { AKANTU_DEBUG_IN(); const Communicator & comm = mesh.getCommunicator(); UInt my_rank = comm.whoAmI(); AKANTU_DEBUG_INFO("Receiving element groups from proc " << root << " TAG(" << Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP) << ")"); CommunicationStatus status; comm.probe<char>(root, Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP), status); CommunicationBuffer buffer(status.size()); comm.receive(buffer, root, Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP)); this->fillElementGroupsFromBuffer(buffer); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/synchronizer/synchronizer.cc b/src/synchronizer/synchronizer.cc index cfc86b95c..4917daf4e 100644 --- a/src/synchronizer/synchronizer.cc +++ b/src/synchronizer/synchronizer.cc @@ -1,56 +1,55 @@ /** * @file synchronizer.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 01 2010 - * @date last modification: Tue Dec 09 2014 + * @date last modification: Wed Nov 15 2017 * * @brief implementation of the common part * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "synchronizer.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <functional> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Synchronizer::Synchronizer(const Communicator & comm, const ID & id, MemoryID memory_id) : Memory(id, memory_id), communicator(comm) { int max_tag = comm.getMaxTag(); this->hash_id = std::hash<std::string>()(this->getID()); if (max_tag != 0) this->hash_id = this->hash_id % max_tag; this->nb_proc = communicator.getNbProc(); this->rank = communicator.whoAmI(); } } // namespace akantu diff --git a/src/synchronizer/synchronizer.hh b/src/synchronizer/synchronizer.hh index 8f3501158..1d1e4cbe4 100644 --- a/src/synchronizer/synchronizer.hh +++ b/src/synchronizer/synchronizer.hh @@ -1,125 +1,125 @@ /** * @file synchronizer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Thu Dec 10 2015 + * @date last modification: Tue Feb 20 2018 * * @brief Common interface for synchronizers * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ + /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_HH__ #define __AKANTU_SYNCHRONIZER_HH__ namespace akantu { class Communicator; } namespace akantu { /* -------------------------------------------------------------------------- */ /* Base class for synchronizers */ /* -------------------------------------------------------------------------- */ class Synchronizer : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Synchronizer(const Communicator & comm, const ID & id = "synchronizer", MemoryID memory_id = 0); Synchronizer(const Synchronizer & other) = default; ~Synchronizer() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronize ghosts without state template <class DataAccessor> void synchronizeOnce(DataAccessor & data_accessor, const SynchronizationTag & tag) const; /// synchronize ghosts template <class DataAccessor> void synchronize(DataAccessor & data_accessor, const SynchronizationTag & tag); /// asynchronous synchronization of ghosts template <class DataAccessor> void asynchronousSynchronize(const DataAccessor & data_accessor, const SynchronizationTag & tag); /// wait end of asynchronous synchronization of ghosts template <class DataAccessor> void waitEndSynchronize(DataAccessor & data_accessor, const SynchronizationTag & tag); /// compute buffer size for a given tag and data accessor template <class DataAccessor> void computeBufferSize(const DataAccessor & data_accessor, const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Communicator, communicator, const Communicator &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the synchronizer ID id; /// hashed version of the id int hash_id; /// message counter per tag std::map<SynchronizationTag, UInt> tag_counter; /// the static memory instance const Communicator & communicator; /// nb processors in the communicator UInt nb_proc; /// rank in the communicator UInt rank; }; } // namespace akantu #include "synchronizer_tmpl.hh" #endif /* __AKANTU_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/synchronizer_impl.hh b/src/synchronizer/synchronizer_impl.hh index fcfedb3e8..1bb1eaf56 100644 --- a/src/synchronizer/synchronizer_impl.hh +++ b/src/synchronizer/synchronizer_impl.hh @@ -1,123 +1,124 @@ /** * @file synchronizer_impl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 24 13:26:47 2016 + * @date creation: Fri Jun 18 2010 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of the generic part of synchronizers * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communications.hh" #include "synchronizer.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_IMPL_HH__ #define __AKANTU_SYNCHRONIZER_IMPL_HH__ namespace akantu { template <class Entity> class SynchronizerImpl : public Synchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SynchronizerImpl(const Communicator & communicator, const ID & id = "synchronizer", MemoryID memory_id = 0); SynchronizerImpl(const SynchronizerImpl & other, const ID & id); ~SynchronizerImpl() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronous synchronization without state virtual void synchronizeOnceImpl(DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) const; /// asynchronous synchronization of ghosts virtual void asynchronousSynchronizeImpl(const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag); /// wait end of asynchronous synchronization of ghosts virtual void waitEndSynchronizeImpl(DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag); /// compute all buffer sizes virtual void computeAllBufferSizes(const DataAccessor<Entity> & data_accessor); /// compute buffer size for a given tag and data accessor virtual void computeBufferSizeImpl(const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ virtual void synchronizeImpl(DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { this->asynchronousSynchronizeImpl(data_accessor, tag); this->waitEndSynchronizeImpl(data_accessor, tag); } /* ------------------------------------------------------------------------ */ /// extract the elements that have a true predicate from in_synchronizer and /// store them in the current synchronizer template <typename Pred> void split(SynchronizerImpl & in_synchronizer, Pred && pred); /// update schemes in a synchronizer template <typename Updater> void updateSchemes(Updater && scheme_updater); /* ------------------------------------------------------------------------ */ virtual UInt sanityCheckDataSize(const Array<Entity> & elements, const SynchronizationTag & tag) const; virtual void packSanityCheckData(CommunicationDescriptor<Entity> & comm_desc) const; virtual void unpackSanityCheckData(CommunicationDescriptor<Entity> & comm_desc) const; public: AKANTU_GET_MACRO(Communications, communications, const Communications<Entity> &); protected: AKANTU_GET_MACRO_NOT_CONST(Communications, communications, Communications<Entity> &); virtual Int getRank(const Entity & entity) const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// information on the communications Communications<Entity> communications; }; } // namespace akantu #include "synchronizer_impl_tmpl.hh" #endif /* __AKANTU_SYNCHRONIZER_IMPL_HH__ */ diff --git a/src/synchronizer/synchronizer_impl_tmpl.hh b/src/synchronizer/synchronizer_impl_tmpl.hh index 7831fbc79..1c919afbd 100644 --- a/src/synchronizer/synchronizer_impl_tmpl.hh +++ b/src/synchronizer/synchronizer_impl_tmpl.hh @@ -1,314 +1,315 @@ /** * @file synchronizer_impl_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 24 13:29:47 2016 + * @date creation: Wed Sep 07 2016 + * @date last modification: Tue Feb 20 2018 * * @brief Implementation of the SynchronizerImpl * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "synchronizer_impl.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ #define __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class Entity> SynchronizerImpl<Entity>::SynchronizerImpl(const Communicator & comm, const ID & id, MemoryID memory_id) : Synchronizer(comm, id, memory_id), communications(comm) {} /* -------------------------------------------------------------------------- */ template <class Entity> SynchronizerImpl<Entity>::SynchronizerImpl(const SynchronizerImpl & other, const ID & id) : Synchronizer(other), communications(other.communications) { this->id = id; } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::synchronizeOnceImpl( DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) const { // no need to synchronize if (this->nb_proc == 1) return; using CommunicationRequests = std::vector<CommunicationRequest>; using CommunicationBuffers = std::map<UInt, CommunicationBuffer>; CommunicationRequests send_requests, recv_requests; CommunicationBuffers send_buffers, recv_buffers; auto postComm = [&](const CommunicationSendRecv & sr, CommunicationBuffers & buffers, CommunicationRequests & requests) -> void { for (auto && pair : communications.iterateSchemes(sr)) { auto & proc = pair.first; const auto & scheme = pair.second; auto & buffer = buffers[proc]; UInt buffer_size = data_accessor.getNbData(scheme, tag); buffer.resize(buffer_size); if (sr == _recv) { requests.push_back(communicator.asyncReceive( buffer, proc, Tag::genTag(this->rank, 0, Tag::_SYNCHRONIZE, this->hash_id))); } else { data_accessor.packData(buffer, scheme, tag); send_requests.push_back(communicator.asyncSend( buffer, proc, Tag::genTag(proc, 0, Tag::_SYNCHRONIZE, this->hash_id))); } } }; // post the receive requests postComm(_recv, recv_buffers, recv_requests); // post the send data requests postComm(_send, send_buffers, send_requests); // treat the receive requests UInt request_ready; while ((request_ready = communicator.waitAny(recv_requests)) != UInt(-1)) { CommunicationRequest & req = recv_requests[request_ready]; UInt proc = req.getSource(); CommunicationBuffer & buffer = recv_buffers[proc]; const auto & scheme = this->communications.getScheme(proc, _recv); data_accessor.unpackData(buffer, scheme, tag); req.free(); recv_requests.erase(recv_requests.begin() + request_ready); } communicator.waitAll(send_requests); communicator.freeCommunicationRequest(send_requests); } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::asynchronousSynchronizeImpl( const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (not this->communications.hasCommunicationSize(tag)) this->computeBufferSize(data_accessor, tag); this->communications.incrementCounter(tag); // Posting the receive ------------------------------------------------------- if (this->communications.hasPendingRecv(tag)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "There must still be some pending receive communications." << " Tag is " << tag << " Cannot start new ones"); } for (auto && comm_desc : this->communications.iterateRecv(tag)) { comm_desc.postRecv(this->hash_id); } // Posting the sends ------------------------------------------------------- if (communications.hasPendingSend(tag)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "There must be some pending sending communications." << " Tag is " << tag); } for (auto && comm_desc : this->communications.iterateSend(tag)) { comm_desc.resetBuffer(); #ifndef AKANTU_NDEBUG this->packSanityCheckData(comm_desc); #endif comm_desc.packData(data_accessor); comm_desc.postSend(this->hash_id); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::waitEndSynchronizeImpl( DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); #ifndef AKANTU_NDEBUG if (this->communications.begin(tag, _recv) != this->communications.end(tag, _recv) && !this->communications.hasPendingRecv(tag)) AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), "No pending communication with the tag \"" << tag); #endif auto recv_end = this->communications.end(tag, _recv); decltype(recv_end) recv_it; while ((recv_it = this->communications.waitAnyRecv(tag)) != recv_end) { auto && comm_desc = *recv_it; #ifndef AKANTU_NDEBUG this->unpackSanityCheckData(comm_desc); #endif comm_desc.unpackData(data_accessor); comm_desc.resetBuffer(); comm_desc.freeRequest(); } this->communications.waitAllSend(tag); this->communications.freeSendRequests(tag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::computeAllBufferSizes( const DataAccessor<Entity> & data_accessor) { for (auto && tag : this->communications.iterateTags()) { this->computeBufferSize(data_accessor, tag); } } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::computeBufferSizeImpl( const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (not this->communications.hasCommunication(tag)) { this->communications.initializeCommunications(tag); AKANTU_DEBUG_ASSERT(communications.hasCommunication(tag) == true, "Communications where not properly initialized"); } for (auto sr : iterate_send_recv) { for (auto && pair : this->communications.iterateSchemes(sr)) { auto proc = pair.first; const auto & scheme = pair.second; UInt size = 0; #ifndef AKANTU_NDEBUG size += this->sanityCheckDataSize(scheme, tag); #endif size += data_accessor.getNbData(scheme, tag); AKANTU_DEBUG_INFO("I have " << size << "(" << printMemorySize<char>(size) << " - " << scheme.size() << " element(s)) data to " << std::string(sr == _recv ? "receive from" : "send to") << proc << " for tag " << tag); this->communications.setCommunicationSize(tag, proc, size, sr); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Entity> template <typename Pred> void SynchronizerImpl<Entity>::split(SynchronizerImpl<Entity> & in_synchronizer, Pred && pred) { AKANTU_DEBUG_IN(); auto filter_list = [&](auto & list, auto & new_list) { auto copy = list; list.resize(0); new_list.resize(0); for (auto && entity : copy) { if (std::forward<Pred>(pred)(entity)) { new_list.push_back(entity); } else { list.push_back(entity); } } }; for (auto sr : iterate_send_recv) { for (auto & scheme_pair : in_synchronizer.communications.iterateSchemes(sr)) { auto proc = scheme_pair.first; auto & scheme = scheme_pair.second; auto & new_scheme = communications.createScheme(proc, sr); filter_list(scheme, new_scheme); } } in_synchronizer.communications.invalidateSizes(); communications.invalidateSizes(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Entity> template <typename Updater> void SynchronizerImpl<Entity>::updateSchemes(Updater && scheme_updater) { for (auto sr : iterate_send_recv) { for (auto & scheme_pair : communications.iterateSchemes(sr)) { auto proc = scheme_pair.first; auto & scheme = scheme_pair.second; std::forward<Updater>(scheme_updater)(scheme, proc, sr); } } communications.invalidateSizes(); } /* -------------------------------------------------------------------------- */ template <class Entity> UInt SynchronizerImpl<Entity>::sanityCheckDataSize( const Array<Entity> &, const SynchronizationTag &) const { return 0; } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::packSanityCheckData( CommunicationDescriptor<Entity> &) const {} /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::unpackSanityCheckData( CommunicationDescriptor<Entity> &) const {} /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ */ diff --git a/src/synchronizer/synchronizer_registry.cc b/src/synchronizer/synchronizer_registry.cc index 3711fa3af..f99fac614 100644 --- a/src/synchronizer/synchronizer_registry.cc +++ b/src/synchronizer/synchronizer_registry.cc @@ -1,121 +1,120 @@ /** * @file synchronizer_registry.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jun 16 2011 - * @date last modification: Thu Oct 08 2015 + * @date last modification: Wed Nov 15 2017 * * @brief Registry of synchronizers * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "synchronizer_registry.hh" #include "synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SynchronizerRegistry::SynchronizerRegistry() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SynchronizerRegistry::~SynchronizerRegistry() { AKANTU_DEBUG_IN(); synchronizers.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SynchronizerRegistry::registerDataAccessor( DataAccessorBase & data_accessor) { this->data_accessor = &data_accessor; } /* -------------------------------------------------------------------------- */ void SynchronizerRegistry::synchronize(SynchronizationTag tag) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(data_accessor != nullptr, "No data accessor set."); std::pair<Tag2Sync::iterator, Tag2Sync::iterator> range = synchronizers.equal_range(tag); for (auto it = range.first; it != range.second; ++it) { it->second->synchronize(*data_accessor, tag); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SynchronizerRegistry::asynchronousSynchronize(SynchronizationTag tag) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(data_accessor != nullptr, "No data accessor set."); std::pair<Tag2Sync::iterator, Tag2Sync::iterator> range = synchronizers.equal_range(tag); for (auto it = range.first; it != range.second; ++it) { (*it).second->asynchronousSynchronize(*data_accessor, tag); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SynchronizerRegistry::waitEndSynchronize(SynchronizationTag tag) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(data_accessor != nullptr, "No data accessor set."); std::pair<Tag2Sync::iterator, Tag2Sync::iterator> range = synchronizers.equal_range(tag); for (auto it = range.first; it != range.second; ++it) { (*it).second->waitEndSynchronize(*data_accessor, tag); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SynchronizerRegistry::registerSynchronizer(Synchronizer & synchronizer, SynchronizationTag tag) { AKANTU_DEBUG_IN(); synchronizers.insert( std::pair<SynchronizationTag, Synchronizer *>(tag, &synchronizer)); AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/synchronizer/synchronizer_registry.hh b/src/synchronizer/synchronizer_registry.hh index 1edf20b9a..54c2026ee 100644 --- a/src/synchronizer/synchronizer_registry.hh +++ b/src/synchronizer/synchronizer_registry.hh @@ -1,91 +1,90 @@ /** * @file synchronizer_registry.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Dec 09 2014 + * @date last modification: Sun Dec 03 2017 * * @brief Registry of synchronizers * * @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) + * Copyright (©) 2010-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_REGISTRY_HH__ #define __AKANTU_SYNCHRONIZER_REGISTRY_HH__ namespace akantu { class DataAccessorBase; class Synchronizer; } namespace akantu { class SynchronizerRegistry { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SynchronizerRegistry(); virtual ~SynchronizerRegistry(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronize operation void synchronize(SynchronizationTag tag); /// asynchronous synchronization void asynchronousSynchronize(SynchronizationTag tag); /// wait end of asynchronous synchronization void waitEndSynchronize(SynchronizationTag tag); /// register a new synchronization void registerSynchronizer(Synchronizer & synchronizer, SynchronizationTag tag); /// Register a different data accessor. void registerDataAccessor(DataAccessorBase & data_accessor); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: using Tag2Sync = std::multimap<SynchronizationTag, Synchronizer *>; /// list of registered synchronization Tag2Sync synchronizers; /// data accessor that will permit to do the pack/unpack things DataAccessorBase * data_accessor{nullptr}; }; } // akantu #endif /* __AKANTU_SYNCHRONIZER_REGISTRY_HH__ */ diff --git a/src/synchronizer/synchronizer_tmpl.hh b/src/synchronizer/synchronizer_tmpl.hh index c7b76c4c7..763cb9070 100644 --- a/src/synchronizer/synchronizer_tmpl.hh +++ b/src/synchronizer/synchronizer_tmpl.hh @@ -1,120 +1,121 @@ /** * @file synchronizer_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * - * @date Wed Aug 3 13:49:36 2016 + * @date creation: Wed Sep 07 2016 + * @date last modification: Thu May 11 2017 * * @brief Implementation of the helper classes for the synchronizer * * @section LICENSE * - * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2016-2018 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 + * 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 + * 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "data_accessor.hh" #include "synchronizer.hh" #include "synchronizer_impl.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_TMPL_HH__ #define __AKANTU_SYNCHRONIZER_TMPL_HH__ namespace akantu { template <class DataAccessorT> void Synchronizer::synchronizeOnce(DataAccessorT & data_accessor, const SynchronizationTag & tag) const { if (const auto * synch_el = dynamic_cast<const SynchronizerImpl<Element> *>(this)) { synch_el->synchronizeOnceImpl( dynamic_cast<DataAccessor<Element> &>(data_accessor), tag); } else if (const auto * synch_dof = dynamic_cast<const SynchronizerImpl<UInt> *>(this)) { synch_dof->synchronizeOnceImpl( dynamic_cast<DataAccessor<UInt> &>(data_accessor), tag); } else { AKANTU_EXCEPTION("You synchronizer is not of a known type"); } } /// synchronize ghosts template <class DataAccessorT> void Synchronizer::synchronize(DataAccessorT & data_accessor, const SynchronizationTag & tag) { if (auto * synch_el = dynamic_cast<SynchronizerImpl<Element> *>(this)) { synch_el->synchronizeImpl( dynamic_cast<DataAccessor<Element> &>(data_accessor), tag); } else if (auto * synch_dof = dynamic_cast<SynchronizerImpl<UInt> *>(this)) { synch_dof->synchronizeImpl( dynamic_cast<DataAccessor<UInt> &>(data_accessor), tag); } else { AKANTU_EXCEPTION("You synchronizer is not of a known type"); } } /* -------------------------------------------------------------------------- */ template <class DataAccessorT> void Synchronizer::asynchronousSynchronize(const DataAccessorT & data_accessor, const SynchronizationTag & tag) { if (auto * synch_el = dynamic_cast<SynchronizerImpl<Element> *>(this)) { synch_el->asynchronousSynchronizeImpl( dynamic_cast<const DataAccessor<Element> &>(data_accessor), tag); } else if (auto * synch_dof = dynamic_cast<SynchronizerImpl<UInt> *>(this)) { synch_dof->asynchronousSynchronizeImpl( dynamic_cast<const DataAccessor<UInt> &>(data_accessor), tag); } else { AKANTU_EXCEPTION("You synchronizer is not of a known type"); } } /* -------------------------------------------------------------------------- */ template <class DataAccessorT> void Synchronizer::waitEndSynchronize(DataAccessorT & data_accessor, const SynchronizationTag & tag) { if (auto * synch_el = dynamic_cast<SynchronizerImpl<Element> *>(this)) { synch_el->waitEndSynchronizeImpl( dynamic_cast<DataAccessor<Element> &>(data_accessor), tag); } else if (auto * synch_dof = dynamic_cast<SynchronizerImpl<UInt> *>(this)) { synch_dof->waitEndSynchronizeImpl( dynamic_cast<DataAccessor<UInt> &>(data_accessor), tag); } else { AKANTU_EXCEPTION("You synchronizer is not of a known type"); } } /// compute buffer size for a given tag and data accessor template <class DataAccessorT> void Synchronizer::computeBufferSize(const DataAccessorT & data_accessor, const SynchronizationTag & tag) { if (auto * synch_el = dynamic_cast<SynchronizerImpl<Element> *>(this)) { synch_el->computeBufferSizeImpl( dynamic_cast<const DataAccessor<Element> &>(data_accessor), tag); } else if (auto * synch_dof = dynamic_cast<SynchronizerImpl<UInt> *>(this)) { synch_dof->computeBufferSizeImpl( dynamic_cast<const DataAccessor<UInt> &>(data_accessor), tag); } else { AKANTU_EXCEPTION("You synchronizer is not of a known type"); } } } // akantu #endif /* __AKANTU_SYNCHRONIZER_TMPL_HH__ */