diff --git a/cmake/AkantuCleaning.cmake b/cmake/AkantuCleaning.cmake index f41eb399e..39202265c 100644 --- a/cmake/AkantuCleaning.cmake +++ b/cmake/AkantuCleaning.cmake @@ -1,77 +1,85 @@ #=============================================================================== # @file AkantuCleaning.cmake # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Thu Jun 1, 2017 # # @brief set of tools to clean the code # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see <http://www.gnu.org/licenses/>. #=============================================================================== # Adding clang-format target if executable is found find_program(CLANG_FORMAT "clang-format") mark_as_advanced(CLANG_FORMAT) macro(register_code_to_format) if(CLANG_FORMAT) add_custom_target( clang-format-all COMMAND ${CLANG_FORMAT} -i -style=file ${ARGN} ) endif() endmacro() # Adding clang-tidy target if executable is found find_program(CLANG_TIDY "clang-tidy") mark_as_advanced(CLANG_TIDY) macro(register_target_to_tidy target) if(CLANG_TIDY) + option(AKANTU_CLANG_TIDY_AUTOFIX OFF) + mark_as_advanced(AKANTU_CLANG_TIDY_AUTOFIX) + + set(_autofix_option) + if(AKANTU_CLANG_TIDY_AUTOFIX) + set(_autofix_option -fix) + endif() get_target_property(_sources ${target} SOURCES) set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "Enable/Disable output of compile commands during generation" FORCE) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/clang-tidy) set(_depends) foreach(_src ${_sources}) get_filename_component(_src_dir ${_src} DIRECTORY) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/clang-tidy/${_src_dir}) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/clang-tidy/${_src}.yaml COMMAND ${CLANG_TIDY} -p=${PROJECT_BINARY_DIR} -export-fixes=${PROJECT_BINARY_DIR}/clang-tidy/${_src}.yaml + ${_autofix_option} ${_src} COMMENT "Tidying ${_src}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) list(APPEND _depends ${PROJECT_BINARY_DIR}/clang-tidy/${_src}.yaml) endforeach() add_custom_target(clang-tidy DEPENDS ${_depends}) endif() endmacro() diff --git a/python/swig/aka_array.i b/python/swig/aka_array.i index cf4838547..117f261fb 100644 --- a/python/swig/aka_array.i +++ b/python/swig/aka_array.i @@ -1,250 +1,248 @@ /** * @file aka_array.i * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Dec 12 2014 * @date last modification: Wed Nov 11 2015 * * @brief wrapper for arrays * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ %{ #define SWIG_FILE_WITH_INIT #include "aka_array.hh" #include "aka_types.hh" %} %include "typemaps.i" namespace akantu { %ignore Array::operator=; %ignore Array::operator[]; %ignore Array::operator(); %ignore Array::set; %ignore Array::begin; %ignore Array::end; %ignore Array::begin_reinterpret; %ignore Array::end_reinterpret; }; %include "aka_array.hh" namespace akantu { - %ignore TensorProxy::operator=; %ignore TensorProxy::operator[]; %ignore TensorProxy::operator(); %ignore Tensor3Proxy::operator=; %ignore Tensor3Proxy::operator[]; %ignore Tensor3Proxy::operator(); %ignore TensorStorage::operator=; %ignore TensorStorage::operator[]; %ignore TensorStorage::operator(); %ignore VectorProxy::operator=; %ignore VectorProxy::operator[]; %ignore VectorProxy::operator(); %ignore MatrixProxy::operator=; %ignore MatrixProxy::operator[]; %ignore MatrixProxy::operator(); %ignore Matrix::operator=; %ignore Matrix::operator[]; %ignore Matrix::operator(); %ignore Tensor3::operator=; %ignore Tensor3::operator[]; %ignore Tensor3::operator(); %ignore Vector::operator=; %ignore Vector::operator[]; %ignore Vector::operator(); %ignore Vector::solve; }; %include "aka_types.hh" namespace akantu { %template(RArray) Array<akantu::Real, true>; %template(UArray) Array<akantu::UInt, true>; %template(BArray) Array<bool, true>; - %template(RVector) Vector<akantu::Real>; }; %include "numpy.i" %init %{ import_array(); %} %inline %{ namespace akantu{ template <typename T> class ArrayForPython : public Array<T>{ public: ArrayForPython(T * wrapped_memory, UInt size = 0, UInt nb_component = 1, const ID & id = "") : Array<T>(0,nb_component,id){ this->values = wrapped_memory; this->size = size; }; ~ArrayForPython(){ this->values = NULL; }; void resize(UInt new_size){ AKANTU_DEBUG_ASSERT(this->size == new_size,"cannot resize a temporary vector"); } }; } template <typename T> int getPythonDataTypeCode(){ AKANTU_EXCEPTION("undefined type");} template <> int 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 <> int getPythonDataTypeCode<double>(){return NPY_DOUBLE;} template <> int getPythonDataTypeCode<long double>(){return NPY_LONGDOUBLE;} template <> int getPythonDataTypeCode<float>(){return NPY_FLOAT;} template <> int getPythonDataTypeCode<unsigned long>(){ int data_typecode = NPY_NOTYPE; size_t s = sizeof(unsigned long); switch(s) { 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 <> int getPythonDataTypeCode<akantu::UInt>(){ int data_typecode = NPY_NOTYPE; size_t s = sizeof(akantu::UInt); switch(s) { 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 <> int getPythonDataTypeCode<int>(){ int data_typecode = NPY_NOTYPE; size_t s = sizeof(int); switch(s) { case 2: data_typecode = NPY_INT16; break; case 4: data_typecode = NPY_INT32; break; case 8: data_typecode = NPY_INT64; break; } return data_typecode; } int getSizeOfPythonType(int type_num){ switch (type_num){ case NPY_INT16 : return 2;break; case NPY_UINT16: return 2;break; case NPY_INT32 : return 4;break; case NPY_UINT32: return 4;break; case NPY_INT64 : return 8;break; case NPY_UINT64: return 8;break; case NPY_FLOAT: return sizeof(float);break; case NPY_DOUBLE: return sizeof(double);break; case NPY_LONGDOUBLE: return sizeof(long double);break; } return 0; } std::string getPythonTypeName(int type_num){ switch (type_num){ case NPY_INT16 : return "NPY_INT16" ;break; case NPY_UINT16: return "NPY_UINT16";break; case NPY_INT32 : return "NPY_INT32" ;break; case NPY_UINT32: return "NPY_UINT32";break; case NPY_INT64 : return "NPY_INT64" ;break; case NPY_UINT64: return "NPY_UINT64";break; case NPY_FLOAT: return "NPY_FLOAT" ;break; case NPY_DOUBLE: return "NPY_DOUBLE";break; case NPY_LONGDOUBLE: return "NPY_LONGDOUBLE";break; } return 0; } template <typename T> void checkDataType(int type_num){ AKANTU_DEBUG_ASSERT(type_num == getPythonDataTypeCode<T>(), "incompatible types between numpy and input function: " << type_num << " != " << getPythonDataTypeCode<T>() << std::endl << getSizeOfPythonType(type_num) << " != " << sizeof(T) << std::endl << "The numpy array is of type " << getPythonTypeName(type_num)); } %} %define %akantu_array_typemaps(DATA_TYPE) %typemap(out, fragment="NumPy_Fragments") (akantu::Array< DATA_TYPE > &) { int data_typecode = getPythonDataTypeCode< DATA_TYPE >(); npy_intp dims[2] = {npy_intp($1->getSize()), npy_intp($1->getNbComponent())}; PyObject* obj = PyArray_SimpleNewFromData(2, dims, data_typecode, $1->storage()); PyArrayObject* array = (PyArrayObject*) obj; if (!array) SWIG_fail; $result = SWIG_Python_AppendOutput($result, obj); } %typemap(in) akantu::Array< DATA_TYPE > & { if (!PyArray_Check($input)) { AKANTU_EXCEPTION("incompatible input which is not a numpy"); } else { PyArray_Descr * numpy_type = (PyArray_Descr*)PyArray_DESCR((PyArrayObject*)$input); int type_num = numpy_type->type_num; checkDataType< DATA_TYPE >(type_num); UInt _n = PyArray_NDIM((PyArrayObject*)$input); if (_n != 2) AKANTU_EXCEPTION("incompatible numpy dimension " << _n); npy_intp * ndims = PyArray_DIMS((PyArrayObject*)$input); akantu::UInt sz = ndims[0]; akantu::UInt nb_components = ndims[1]; PyArrayIterObject *iter = (PyArrayIterObject *)PyArray_IterNew($input); if (iter == NULL) AKANTU_EXCEPTION("Python internal error"); $1 = new akantu::ArrayForPython< DATA_TYPE >((DATA_TYPE*)(iter->dataptr),sz,nb_components,"tmp_array_for_python"); } } %enddef %akantu_array_typemaps(double ) %akantu_array_typemaps(float ) %akantu_array_typemaps(unsigned int) %akantu_array_typemaps(unsigned long) %akantu_array_typemaps(int ) %akantu_array_typemaps(bool ) diff --git a/src/common/aka_array.hh b/src/common/aka_array.hh index 16a0ac321..646801a86 100644 --- a/src/common/aka_array.hh +++ b/src/common/aka_array.hh @@ -1,363 +1,365 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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>{}> 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[]); /// append a Vector or a Matrix template <template <typename> class C, typename = std::enable_if_t<is_tensor<C<T>>{}>> 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); /// 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; /// @see Array::find(const_reference elem) const template <template <typename> class C, typename = std::enable_if_t<is_tensor<C<T>>{}>> inline UInt find(const C<T> & elem); /// 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); } /// 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>>{}>> inline void set(const C<T> & vm); /// 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 eb9b21b7e..9a2c7b0bb 100644 --- a/src/common/aka_array_tmpl.hh +++ b/src/common/aka_array_tmpl.hh @@ -1,1252 +1,1252 @@ /** * @file aka_array_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jul 15 2010 * @date last modification: Fri Jan 22 2016 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ /* 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); // } /* -------------------------------------------------------------------------- */ /** * 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); } /* -------------------------------------------------------------------------- */ /** * 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 */ 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; } /* -------------------------------------------------------------------------- */ /** * 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); } /* -------------------------------------------------------------------------- */ /** * 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); } } /* -------------------------------------------------------------------------- */ 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(NULL) { + : 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(NULL) { + : 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 == NULL) { + 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 != NULL, + tmp_ptr != nullptr, "Cannot allocate " << printMemorySize<T>(size_to_alloc * nb_component)); - if (tmp_ptr == NULL) { + if (tmp_ptr == nullptr) { AKANTU_DEBUG_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_DEBUG_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; } /* -------------------------------------------------------------------------- */ /* 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_DEBUG_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) -> typename std::common_type<V...>::type { typename std::common_type<V...>::type 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<Arr>::value, typename array_type::template const_iterator<type>, typename array_type::template iterator<type>>; if (array.getNbComponent() * array.size() != product_all(std::forward<Ns>(ns)...)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::ArrayException(), "The iterator on Array " << 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::forward<Ns>(ns)...){}; decltype(auto) begin() { 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) size() { return std::get<std::tuple_size<tuple>::value - 1>(sizes); } private: Array array; tuple sizes; }; } // namespace detail /* -------------------------------------------------------------------------- */ template <typename Array, typename... Ns> decltype(auto) make_view(Array && array, Ns &&... ns) { auto size = std::forward<decltype(array)>(array).size() * std::forward<decltype(array)>(array).getNbComponent() / detail::product_all(ns...); return detail::ArrayView<Array, Ns..., decltype(size)>( std::forward<Array>(array), std::forward<Ns>(ns)..., std::forward<decltype(size)>(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: typedef iterator_internal<const R, const_iterator, R> parent; 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>{}>> 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>{}> 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; } } // namespace akantu #endif /* __AKANTU_AKA_ARRAY_TMPL_HH__ */ diff --git a/src/common/aka_common.cc b/src/common/aka_common.cc index 7e61edc3b..9f42be2d3 100644 --- a/src/common/aka_common.cc +++ b/src/common/aka_common.cc @@ -1,155 +1,155 @@ /** * @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 * * @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) * * Akantu is free 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 "aka_common.hh" #include "aka_static_memory.hh" #include "communicator.hh" #include "aka_random_generator.hh" #include "parser.hh" #include "cppargparse.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(NULL); + 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(_st_user).first); } std::unique_ptr<Communicator> Communicator::static_communicator; } // akantu diff --git a/src/common/aka_csr.hh b/src/common/aka_csr.hh index e88f9a02c..2422d5b44 100644 --- a/src/common/aka_csr.hh +++ b/src/common/aka_csr.hh @@ -1,259 +1,259 @@ /** * @file aka_csr.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Apr 20 2011 * @date last modification: Sun Oct 19 2014 * * @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) * * Akantu is free 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 "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(){}; /* ------------------------------------------------------------------------ */ /* 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: typedef std::iterator<std::bidirectional_iterator_tag, R> _parent; typedef typename _parent::pointer pointer; typedef typename _parent::reference reference; - explicit iterator_internal(pointer x = NULL) : pos(x){}; + 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; }; typedef iterator_internal<T> iterator; typedef iterator_internal<const T> const_iterator; 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_error.cc b/src/common/aka_error.cc index cb0346ce0..04209802d 100644 --- a/src/common/aka_error.cc +++ b/src/common/aka_error.cc @@ -1,355 +1,355 @@ /** * @file aka_error.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Sep 06 2010 * @date last modification: Tue Jan 19 2016 * * @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) * * Akantu is free 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 "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, NULL, 0, &status)) != - NULL) { + 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(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) != NULL) + 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; size_t 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) location = exec(std::string(BOOST_PP_STRINGIZE(READLINK_COMMAND)) + std::string(" -f ") + location); #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) std::map<std::string, size_t>::iterator 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; } std::ofstream * 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_random_generator.hh b/src/common/aka_random_generator.hh index 3fada453f..73fa4952b 100644 --- a/src/common/aka_random_generator.hh +++ b/src/common/aka_random_generator.hh @@ -1,265 +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 * * @brief generic random generator * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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_static_memory.cc b/src/common/aka_static_memory.cc index 7d8709f47..d9d258834 100644 --- a/src/common/aka_static_memory.cc +++ b/src/common/aka_static_memory.cc @@ -1,156 +1,156 @@ /** * @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 * * @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) * * Akantu is free 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 <stdexcept> #include <sstream> /* -------------------------------------------------------------------------- */ #include "aka_static_memory.hh" /* -------------------------------------------------------------------------- */ namespace akantu { bool StaticMemory::is_instantiated = false; -StaticMemory * StaticMemory::single_static_memory = NULL; +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 = NULL; + StaticMemory::single_static_memory = nullptr; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StaticMemory::sfree(const MemoryID & memory_id, const ID & name) { AKANTU_DEBUG_IN(); try { ArrayMap & 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_types.hh b/src/common/aka_types.hh index bd65ef234..87eed2533 100644 --- a/src/common/aka_types.hh +++ b/src/common/aka_types.hh @@ -1,1263 +1,1263 @@ /** * @file aka_types.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 17 2011 * @date last modification: Fri Jan 22 2016 * * @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) * * Akantu is free 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 "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; TensorProxy(T * data, UInt m, UInt n, UInt p) { DimHelper<ndim>::setDims(m, n, p, this->n); this->values = data; } 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); } public: using RetType = _RetType; //operator RetType() { return RetType(static_cast<RetTypeProxy &>(*this)); } 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; } 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 <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: 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>> { typedef TensorProxy<T, 3, Tensor3<T>> parent; using type = Tensor3<T>; public: Tensor3Proxy(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; } protected: TensorStorage(const TensorStorage & src) = delete; public: TensorStorage(const TensorStorage & src, bool deep_copy) : values(nullptr), wrapped(false) { 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>> { typedef TensorStorage<T, 1, Vector<T>> parent; 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 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 void normalize() { Real n = norm(); operator/=(n); } /* ------------------------------------------------------------------------ */ /// 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>> { typedef TensorStorage<T, 2, Matrix<T>> parent; 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; } } - virtual ~Matrix() = default; + ~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 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() != NULL) + 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 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_DEBUG_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>> { typedef TensorStorage<T, 3, Tensor3<T>> parent; 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) {} 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/fe_engine/cohesive_element.cc b/src/fe_engine/cohesive_element.cc index 97c4df49c..9a7073e13 100644 --- a/src/fe_engine/cohesive_element.cc +++ b/src/fe_engine/cohesive_element.cc @@ -1,151 +1,176 @@ /** * @file cohesive_element.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Sun Sep 26 2010 * @date last modification: Mon Sep 14 2015 * * @brief CohesiveElement 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) * * Akantu is free 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 "aka_common.hh" #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ -template<> UInt GeometricalElement<_gt_cohesive_2d_4>::spatial_dimension = 2; -template<> UInt GeometricalElement<_gt_cohesive_2d_4>::nb_nodes_per_element = 4; -template<> UInt GeometricalElement<_gt_cohesive_2d_4>::nb_facet_types = 1; -template<> UInt GeometricalElement<_gt_cohesive_2d_4>::nb_facets[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_2d_4>::nb_nodes_per_facet[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_2d_4>::facet_connectivity_vect[] = {0, 2, - 1, 3}; -template<> UInt * GeometricalElement<_gt_cohesive_2d_4>::facet_connectivity[] = { &facet_connectivity_vect[0] }; - -template<> ElementType ElementClass<_cohesive_2d_4>::facet_type[] = { _segment_2 }; -template<> ElementType ElementClass<_cohesive_2d_4>::p1_type = _cohesive_2d_4; +template <> UInt GeometricalElement<_gt_cohesive_2d_4>::spatial_dimension = 2; +template <> UInt GeometricalElement<_gt_cohesive_2d_4>::nb_nodes_per_element = 4; +template <> UInt GeometricalElement<_gt_cohesive_2d_4>::nb_facet_types = 1; +template <> UInt GeometricalElement<_gt_cohesive_2d_4>::nb_facets[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_2d_4>::nb_nodes_per_facet[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_2d_4>::facet_connectivity_vect[] = {0, 2, + 1, 3}; +template <> +UInt * GeometricalElement<_gt_cohesive_2d_4>::facet_connectivity[] = { + &facet_connectivity_vect[0]}; + +template <> +ElementType ElementClass<_cohesive_2d_4>::facet_type[] = {_segment_2}; +template <> ElementType ElementClass<_cohesive_2d_4>::p1_type = _cohesive_2d_4; /* -------------------------------------------------------------------------- */ -template<> UInt GeometricalElement<_gt_cohesive_2d_6>::spatial_dimension = 2; -template<> UInt GeometricalElement<_gt_cohesive_2d_6>::nb_nodes_per_element = 6; -template<> UInt GeometricalElement<_gt_cohesive_2d_6>::nb_facet_types = 1; -template<> UInt GeometricalElement<_gt_cohesive_2d_6>::nb_facets[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_2d_6>::nb_nodes_per_facet[] = { 3 }; -template<> UInt GeometricalElement<_gt_cohesive_2d_6>::facet_connectivity_vect[] = {0, 3, - 1, 4, - 2, 5}; -template<> UInt * GeometricalElement<_gt_cohesive_2d_6>::facet_connectivity[] = { &facet_connectivity_vect[0] }; - -template<> ElementType ElementClass<_cohesive_2d_6>::facet_type[] = { _segment_3 }; -template<> ElementType ElementClass<_cohesive_2d_6>::p1_type = _cohesive_2d_4; +template <> UInt GeometricalElement<_gt_cohesive_2d_6>::spatial_dimension = 2; +template <> +UInt GeometricalElement<_gt_cohesive_2d_6>::nb_nodes_per_element = 6; +template <> UInt GeometricalElement<_gt_cohesive_2d_6>::nb_facet_types = 1; +template <> UInt GeometricalElement<_gt_cohesive_2d_6>::nb_facets[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_2d_6>::nb_nodes_per_facet[] = {3}; +template <> +UInt GeometricalElement<_gt_cohesive_2d_6>::facet_connectivity_vect[] = { + 0, 3, 1, 4, 2, 5}; +template <> +UInt * GeometricalElement<_gt_cohesive_2d_6>::facet_connectivity[] = { + &facet_connectivity_vect[0]}; + +template <> +ElementType ElementClass<_cohesive_2d_6>::facet_type[] = {_segment_3}; +template <> ElementType ElementClass<_cohesive_2d_6>::p1_type = _cohesive_2d_4; /* -------------------------------------------------------------------------- */ -template<> UInt GeometricalElement<_gt_cohesive_1d_2>::spatial_dimension = 1; -template<> UInt GeometricalElement<_gt_cohesive_1d_2>::nb_nodes_per_element = 2; -template<> UInt GeometricalElement<_gt_cohesive_1d_2>::nb_facet_types = 1; -template<> UInt GeometricalElement<_gt_cohesive_1d_2>::nb_facets[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_1d_2>::nb_nodes_per_facet[] = { 1 }; -template<> UInt GeometricalElement<_gt_cohesive_1d_2>::facet_connectivity_vect[] = {0, - 1}; -template<> UInt * GeometricalElement<_gt_cohesive_1d_2>::facet_connectivity[] = { &facet_connectivity_vect[0] }; - -template<> ElementType ElementClass<_cohesive_1d_2>::facet_type[] = { _point_1 }; -template<> ElementType ElementClass<_cohesive_1d_2>::p1_type = _cohesive_1d_2; +template <> UInt GeometricalElement<_gt_cohesive_1d_2>::spatial_dimension = 1; +template <> +UInt GeometricalElement<_gt_cohesive_1d_2>::nb_nodes_per_element = 2; +template <> UInt GeometricalElement<_gt_cohesive_1d_2>::nb_facet_types = 1; +template <> UInt GeometricalElement<_gt_cohesive_1d_2>::nb_facets[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_1d_2>::nb_nodes_per_facet[] = {1}; +template <> +UInt GeometricalElement<_gt_cohesive_1d_2>::facet_connectivity_vect[] = {0, 1}; +template <> +UInt * GeometricalElement<_gt_cohesive_1d_2>::facet_connectivity[] = { + &facet_connectivity_vect[0]}; + +template <> ElementType ElementClass<_cohesive_1d_2>::facet_type[] = {_point_1}; +template <> ElementType ElementClass<_cohesive_1d_2>::p1_type = _cohesive_1d_2; /* -------------------------------------------------------------------------- */ -template<> UInt GeometricalElement<_gt_cohesive_3d_6>::spatial_dimension = 3; -template<> UInt GeometricalElement<_gt_cohesive_3d_6>::nb_nodes_per_element = 6; -template<> UInt GeometricalElement<_gt_cohesive_3d_6>::nb_facet_types = 1; -template<> UInt GeometricalElement<_gt_cohesive_3d_6>::nb_facets[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_6>::nb_nodes_per_facet[] = { 3 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_6>::facet_connectivity_vect[] = {0, 3, - 1, 4, - 2, 5}; -template<> UInt * GeometricalElement<_gt_cohesive_3d_6>::facet_connectivity[] = { &facet_connectivity_vect[0] }; - -template<> ElementType ElementClass<_cohesive_3d_6>::facet_type[] = { _triangle_3 }; -template<> ElementType ElementClass<_cohesive_3d_6>::p1_type = _cohesive_3d_6; +template <> UInt GeometricalElement<_gt_cohesive_3d_6>::spatial_dimension = 3; +template <> +UInt GeometricalElement<_gt_cohesive_3d_6>::nb_nodes_per_element = 6; +template <> UInt GeometricalElement<_gt_cohesive_3d_6>::nb_facet_types = 1; +template <> UInt GeometricalElement<_gt_cohesive_3d_6>::nb_facets[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_6>::nb_nodes_per_facet[] = {3}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_6>::facet_connectivity_vect[] = { + 0, 3, 1, 4, 2, 5}; +template <> +UInt * GeometricalElement<_gt_cohesive_3d_6>::facet_connectivity[] = { + &facet_connectivity_vect[0]}; + +template <> +ElementType ElementClass<_cohesive_3d_6>::facet_type[] = {_triangle_3}; +template <> ElementType ElementClass<_cohesive_3d_6>::p1_type = _cohesive_3d_6; /* -------------------------------------------------------------------------- */ -template<> UInt GeometricalElement<_gt_cohesive_3d_12>::spatial_dimension = 3; -template<> UInt GeometricalElement<_gt_cohesive_3d_12>::nb_nodes_per_element = 12; -template<> UInt GeometricalElement<_gt_cohesive_3d_12>::nb_facet_types = 1; -template<> UInt GeometricalElement<_gt_cohesive_3d_12>::nb_facets[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_12>::nb_nodes_per_facet[] = { 6 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_12>::facet_connectivity_vect[] = {0, 6, - 1, 7, - 2, 8, - 3, 9, - 4, 10, - 5, 11}; -template<> UInt * GeometricalElement<_gt_cohesive_3d_12>::facet_connectivity[] = { &facet_connectivity_vect[0] }; - -template<> ElementType ElementClass<_cohesive_3d_12>::facet_type[] = { _triangle_6 }; -template<> ElementType ElementClass<_cohesive_3d_12>::p1_type = _cohesive_3d_6; +template <> UInt GeometricalElement<_gt_cohesive_3d_12>::spatial_dimension = 3; +template <> +UInt GeometricalElement<_gt_cohesive_3d_12>::nb_nodes_per_element = 12; +template <> UInt GeometricalElement<_gt_cohesive_3d_12>::nb_facet_types = 1; +template <> UInt GeometricalElement<_gt_cohesive_3d_12>::nb_facets[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_12>::nb_nodes_per_facet[] = {6}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_12>::facet_connectivity_vect[] = { + 0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11}; +template <> +UInt * GeometricalElement<_gt_cohesive_3d_12>::facet_connectivity[] = { + &facet_connectivity_vect[0]}; + +template <> +ElementType ElementClass<_cohesive_3d_12>::facet_type[] = {_triangle_6}; +template <> ElementType ElementClass<_cohesive_3d_12>::p1_type = _cohesive_3d_6; /* -------------------------------------------------------------------------- */ -template<> UInt GeometricalElement<_gt_cohesive_3d_8>::spatial_dimension = 3; -template<> UInt GeometricalElement<_gt_cohesive_3d_8>::nb_nodes_per_element = 8; -template<> UInt GeometricalElement<_gt_cohesive_3d_8>::nb_facet_types = 1; -template<> UInt GeometricalElement<_gt_cohesive_3d_8>::nb_facets[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_8>::nb_nodes_per_facet[] = { 4 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_8>::facet_connectivity_vect[] = {0, 4, - 1, 5, - 2, 6, - 3, 7}; -template<> UInt * GeometricalElement<_gt_cohesive_3d_8>::facet_connectivity[] = { &facet_connectivity_vect[0] }; - -template<> ElementType ElementClass<_cohesive_3d_8>::facet_type[] = { _quadrangle_4 }; -template<> ElementType ElementClass<_cohesive_3d_8>::p1_type = _cohesive_3d_8; +template <> UInt GeometricalElement<_gt_cohesive_3d_8>::spatial_dimension = 3; +template <> +UInt GeometricalElement<_gt_cohesive_3d_8>::nb_nodes_per_element = 8; +template <> UInt GeometricalElement<_gt_cohesive_3d_8>::nb_facet_types = 1; +template <> UInt GeometricalElement<_gt_cohesive_3d_8>::nb_facets[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_8>::nb_nodes_per_facet[] = {4}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_8>::facet_connectivity_vect[] = { + 0, 4, 1, 5, 2, 6, 3, 7}; +template <> +UInt * GeometricalElement<_gt_cohesive_3d_8>::facet_connectivity[] = { + &facet_connectivity_vect[0]}; + +template <> +ElementType ElementClass<_cohesive_3d_8>::facet_type[] = {_quadrangle_4}; +template <> ElementType ElementClass<_cohesive_3d_8>::p1_type = _cohesive_3d_8; /* -------------------------------------------------------------------------- */ -template<> UInt GeometricalElement<_gt_cohesive_3d_16>::spatial_dimension = 3; -template<> UInt GeometricalElement<_gt_cohesive_3d_16>::nb_nodes_per_element = 16; -template<> UInt GeometricalElement<_gt_cohesive_3d_16>::nb_facet_types = 1; -template<> UInt GeometricalElement<_gt_cohesive_3d_16>::nb_facets[] = { 2 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_16>::nb_nodes_per_facet[] = { 8 }; -template<> UInt GeometricalElement<_gt_cohesive_3d_16>::facet_connectivity_vect[] = {0, 8, - 1, 9, - 2, 10, - 3, 11, - 4, 12, - 5, 13, - 6, 14, - 7, 15}; -template<> UInt * GeometricalElement<_gt_cohesive_3d_16>::facet_connectivity[] = { &facet_connectivity_vect[0] }; - -template<> ElementType ElementClass<_cohesive_3d_16>::facet_type[] = { _quadrangle_8 }; -template<> ElementType ElementClass<_cohesive_3d_16>::p1_type = _cohesive_3d_8; +template <> UInt GeometricalElement<_gt_cohesive_3d_16>::spatial_dimension = 3; +template <> +UInt GeometricalElement<_gt_cohesive_3d_16>::nb_nodes_per_element = 16; +template <> UInt GeometricalElement<_gt_cohesive_3d_16>::nb_facet_types = 1; +template <> UInt GeometricalElement<_gt_cohesive_3d_16>::nb_facets[] = {2}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_16>::nb_nodes_per_facet[] = {8}; +template <> +UInt GeometricalElement<_gt_cohesive_3d_16>::facet_connectivity_vect[] = { + 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15}; +template <> +UInt * GeometricalElement<_gt_cohesive_3d_16>::facet_connectivity[] = { + &facet_connectivity_vect[0]}; + +template <> +ElementType ElementClass<_cohesive_3d_16>::facet_type[] = {_quadrangle_8}; +template <> ElementType ElementClass<_cohesive_3d_16>::p1_type = _cohesive_3d_8; /* -------------------------------------------------------------------------- */ -} // akantu +} // namespace akantu diff --git a/src/fe_engine/element_class.hh b/src/fe_engine/element_class.hh index 188115a3d..6cb694cda 100644 --- a/src/fe_engine/element_class.hh +++ b/src/fe_engine/element_class.hh @@ -1,410 +1,408 @@ /** * @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 * * @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) * * Akantu is free 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 "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}; \ + 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); /* -------------------------------------------------------------------------- */ /// Templated GeometricalElement with function getInradius template <GeometricalType geometrical_type, GeometricalShapeType shape = GeometricalShape<geometrical_type>::shape> class GeometricalElement { public: /// compute the in-radius static inline Real getInradius(__attribute__((unused)) const Matrix<Real> & coord) { AKANTU_DEBUG_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, spatial_dimension, UInt); static AKANTU_GET_MACRO_NOT_CONST(NbNodesPerElement, nb_nodes_per_element, UInt); static AKANTU_GET_MACRO_NOT_CONST(NbFacetTypes, nb_facet_types, UInt); static inline UInt getNbFacetsPerElement(UInt t); static inline UInt getNbFacetsPerElement(); static inline const MatrixProxy<UInt> getFacetLocalConnectivityPerElement(UInt t = 0); protected: /// Number of nodes per element static UInt nb_nodes_per_element; /// spatial dimension of the element static UInt spatial_dimension; /// number of different facet types static UInt nb_facet_types; /// number of facets for element static UInt nb_facets[]; + /// Nb nodes per facets types + static UInt nb_nodes_per_facet[]; /// storage of the facet local connectivity static UInt facet_connectivity_vect[]; /// local connectivity of facets static UInt * facet_connectivity[]; - -private: - /// Type of the facet elements - static UInt nb_nodes_per_facet[]; }; /* -------------------------------------------------------------------------- */ /* Interpolation */ /* -------------------------------------------------------------------------- */ /// default InterpolationProperty structure template <InterpolationType interpolation_type> struct InterpolationProperty { static const InterpolationKind kind{_itk_not_defined}; static const UInt nb_nodes_per_element{0}; static const UInt natural_space_dimension{0}; }; /// 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 const InterpolationKind kind{itp_kind}; \ static const UInt nb_nodes_per_element{nb_nodes}; \ static const 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: typedef InterpolationProperty<interpolation_type> interpolation_property; /// 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_DEBUG_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_DEBUG_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_DEBUG_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: typedef GeometricalElement< ElementClassProperty<element_type>::geometrical_type> geometrical_element; typedef InterpolationElement< ElementClassProperty<element_type>::interpolation_type> interpolation_element; typedef ElementClassProperty<element_type> element_property; typedef typename interpolation_element::interpolation_property 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 AKANTU_GET_MACRO_NOT_CONST( SpatialDimension, ElementClassProperty<element_type>::spatial_dimension, UInt); static AKANTU_GET_MACRO_NOT_CONST(P1ElementType, p1_type, const ElementType &); static const ElementType & getFacetType(UInt t = 0) { return facet_type[t]; } static ElementType * getFacetTypeInternal() { return facet_type; } protected: /// Type of the facet elements static ElementType facet_type[]; /// type of element P1 associated static ElementType p1_type; }; /* -------------------------------------------------------------------------- */ } // namespace akantu /* -------------------------------------------------------------------------- */ #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/fe_engine.hh b/src/fe_engine/fe_engine.hh index 2c6fffa42..9ca9a0343 100644 --- a/src/fe_engine/fe_engine.hh +++ b/src/fe_engine/fe_engine.hh @@ -1,384 +1,384 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FE_ENGINE_HH__ #define __AKANTU_FE_ENGINE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "element_type_map.hh" #include "mesh_events.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, ID id = "fem", MemoryID memory_id = 0); - virtual ~FEEngine(); + ~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 = NULL) const = 0; + const ElementTypeMapArray<UInt> * filter_elements = nullptr) 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 = NULL) const = 0; + 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_DEBUG_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_DEBUG_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_DEBUG_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_DEBUG_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_template.hh b/src/fe_engine/fe_engine_template.hh index 026963159..5b8c0e502 100644 --- a/src/fe_engine/fe_engine_template.hh +++ b/src/fe_engine/fe_engine_template.hh @@ -1,393 +1,395 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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: typedef I<kind, IntegrationOrderFunctor> Integ; typedef S<kind> Shape; FEEngineTemplate(Mesh & mesh, UInt spatial_dimension = _all_dimensions, ID id = "fem", MemoryID memory_id = 0); - virtual ~FEEngineTemplate(); + ~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" - virtual Real - integrate(const Vector<Real> & f, const ElementType & type, UInt index, - const GhostType & ghost_type = _not_ghost) const override; + 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 = NULL) const override; + const ElementTypeMapArray<UInt> * filter_elements = + nullptr) 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 = NULL) const override; + 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 = NULL) const override; + 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; #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_tmpl.hh b/src/fe_engine/fe_engine_template_tmpl.hh index 48637bec3..83e0f168e 100644 --- a/src/fe_engine/fe_engine_template_tmpl.hh +++ b/src/fe_engine/fe_engine_template_tmpl.hh @@ -1,1301 +1,1301 @@ /** * @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 * * @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) * * Akantu is free 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 "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() {} /* -------------------------------------------------------------------------- */ /** * 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_DEBUG_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_DEBUG_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 = NULL; + 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(); } /* -------------------------------------------------------------------------- */ 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_DEBUG_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_DEBUG_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) { + 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_DEBUG_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_DEBUG_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_DEBUG_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_DEBUG_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_DEBUG_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/integration_point.hh b/src/fe_engine/integration_point.hh index b03973307..2e6314ce7 100644 --- a/src/fe_engine/integration_point.hh +++ b/src/fe_engine/integration_point.hh @@ -1,167 +1,168 @@ /** * @file integration_point.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Jun 17 2015 * @date last modification: Sun Nov 15 2015 * * @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) * * Akantu is free 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 "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: typedef Vector<Real> position_type; /* ------------------------------------------------------------------------ */ /* 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), global_num(0), 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; // 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 8374f1415..5df11d185 100644 --- a/src/fe_engine/integrator.hh +++ b/src/fe_engine/integrator.hh @@ -1,137 +1,137 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ #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(); }; - virtual ~Integrator(){}; + ~Integrator() override{}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// empty method template <ElementType type> inline void precomputeJacobiansOnQuadraturePoints(__attribute__((unused)) GhostType ghost_type) {} /// empty method void integrateOnElement(__attribute__((unused)) const Array<Real> & f, __attribute__((unused)) Real * intf, __attribute__((unused)) UInt nb_degree_of_freedom, __attribute__((unused)) const Element & elem, __attribute__((unused)) 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 d35db8ed3..b6f09fa1e 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 * * @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) * * Akantu is free 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 "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); - virtual ~IntegratorGauss(){}; + ~IntegratorGauss() override{}; /* ------------------------------------------------------------------------ */ /* 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/shape_cohesive.hh b/src/fe_engine/shape_cohesive.hh index 38e512944..d214f7035 100644 --- a/src/fe_engine/shape_cohesive.hh +++ b/src/fe_engine/shape_cohesive.hh @@ -1,169 +1,169 @@ /** * @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 * * @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) * * Akantu is free 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 "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); - virtual ~ShapeLagrange() = default; + ~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); } /// 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_DEBUG_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_functions.hh b/src/fe_engine/shape_functions.hh index ccdac5dce..f7d130af6 100644 --- a/src/fe_engine/shape_functions.hh +++ b/src/fe_engine/shape_functions.hh @@ -1,214 +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 * * @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) * * Akantu is free 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 "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); - virtual ~ShapeFunctions() = default; + ~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); 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_DEBUG_TO_IMPLEMENT(); } virtual void onElementsRemoved(const Array<Element> &, const ElementTypeMapArray<UInt> &) { AKANTU_DEBUG_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_lagrange.hh b/src/fe_engine/shape_lagrange.hh index 3973aeeb9..565a00f74 100644 --- a/src/fe_engine/shape_lagrange.hh +++ b/src/fe_engine/shape_lagrange.hh @@ -1,162 +1,162 @@ /** * @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 * * @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) * * Akantu is free 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 "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); - virtual ~ShapeLagrange() = default; + ~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; /// 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.hh b/src/fe_engine/shape_lagrange_base.hh index 2d3a0ab8c..08d915f7d 100644 --- a/src/fe_engine/shape_lagrange_base.hh +++ b/src/fe_engine/shape_lagrange_base.hh @@ -1,91 +1,91 @@ /** * @file shape_lagrange_base.hh * * @author Nicolas Richart * * @date creation Thu Jul 27 2017 * * @brief Base class for the shape lagrange * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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); - virtual ~ShapeLagrangeBase(); + ~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/io/dumper/dumper_compute.hh b/src/io/dumper/dumper_compute.hh index a55f37291..2f7931dd7 100644 --- a/src/io/dumper/dumper_compute.hh +++ b/src/io/dumper/dumper_compute.hh @@ -1,272 +1,272 @@ /** * @file dumper_compute.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Tue Sep 02 2014 * @date last modification: Tue Jan 19 2016 * * @brief Field that map a function to another field * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_COMPUTE_HH__ #define __AKANTU_DUMPER_COMPUTE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dumper_iohelper.hh" #include "dumper_type_traits.hh" #include "dumper_field.hh" #include <io_helper.hh> /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ class ComputeFunctorInterface { public: virtual ~ComputeFunctorInterface(){}; virtual UInt getDim() = 0; virtual UInt getNbComponent(UInt old_nb_comp) = 0; }; /* -------------------------------------------------------------------------- */ template <typename return_type> class ComputeFunctorOutput : public ComputeFunctorInterface { public: ComputeFunctorOutput(){}; - virtual ~ComputeFunctorOutput(){}; + ~ComputeFunctorOutput() override{}; }; /* -------------------------------------------------------------------------- */ template <typename input_type, typename return_type> class ComputeFunctor : public ComputeFunctorOutput<return_type> { public: ComputeFunctor(){}; - virtual ~ComputeFunctor(){}; + ~ComputeFunctor() override{}; virtual return_type func(const input_type & d, Element global_index) = 0; }; /* -------------------------------------------------------------------------- */ template <typename SubFieldCompute, typename _return_type> class FieldCompute : public Field { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: typedef typename SubFieldCompute::iterator sub_iterator; typedef typename SubFieldCompute::types sub_types; typedef typename sub_types::return_type sub_return_type; typedef _return_type return_type; typedef typename sub_types::data_type data_type; typedef TypeTraits<data_type, return_type, ElementTypeMapArray<data_type> > types; 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() { + ~FieldCompute() override { delete &(this->sub_field); delete &(this->func); } - virtual void registerToDumper(const std::string & id, - iohelper::Dumper & dumper) { + 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; } - virtual void checkHomogeneity() { this->homogeneous = true; }; + void checkHomogeneity() override { this->homogeneous = true; }; iohelper::DataType getDataType() { return iohelper::getDataType<data_type>(); } /// get the number of components of the hosted field - virtual ElementTypeMap<UInt> + ElementTypeMap<UInt> getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, - ElementKind kind = _ek_not_defined) { + 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 virtual Field * connect(FieldComputeProxy & proxy); + inline Field * connect(FieldComputeProxy & proxy) override; /// for connection to a FieldCompute - virtual ComputeFunctorInterface * connect(HomogenizerProxy & proxy); + 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) { FieldCompute<T, output> * 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 NULL; + 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 NULL; + 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_partition.hh b/src/io/dumper/dumper_element_partition.hh index ff8aa2654..79c8b9ced 100644 --- a/src/io/dumper/dumper_element_partition.hh +++ b/src/io/dumper/dumper_element_partition.hh @@ -1,124 +1,124 @@ /** * @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 * * @brief ElementPartition field * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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: typedef element_iterator<types, dumper::element_partition_field_iterator> parent; typedef typename types::return_type return_type; typedef typename types::array_iterator array_iterator; typedef typename types::field_type 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 */ /* ------------------------------------------------------------------------ */ typedef SingleType<UInt,Vector,filtered> types; typedef element_partition_field_iterator<types> iterator; typedef GenericElementalField<types,element_partition_field_iterator> parent; typedef typename types::field_type 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() { return 1; } + UInt getDim() override { return 1; } }; /* -------------------------------------------------------------------------- */ __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 383b8b575..ab5ee3886 100644 --- a/src/io/dumper/dumper_generic_elemental_field.hh +++ b/src/io/dumper/dumper_generic_elemental_field.hh @@ -1,224 +1,224 @@ /** * @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 * * @brief Generic interface for elemental fields * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ #ifndef __AKANTU_DUMPER_GENERIC_ELEMENTAL_FIELD_HH__ #define __AKANTU_DUMPER_GENERIC_ELEMENTAL_FIELD_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_field.hh" #include "element_type_map_filter.hh" #include "dumper_element_iterator.hh" #include "dumper_homogenizing_field.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 typedef _types types; typedef typename types::data_type data_type; typedef typename types::it_type it_type; typedef typename types::field_type field_type; typedef typename types::array_type array_type; typedef typename types::array_iterator array_iterator; typedef typename field_type::type_iterator field_type_iterator; typedef iterator_type<types> iterator; /* ------------------------------------------------------------------------ */ /* 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 - virtual ElementTypeMap<UInt> + ElementTypeMap<UInt> getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, - ElementKind kind = _ek_not_defined) { + 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 - virtual void checkHomogeneity(); + void checkHomogeneity() override; public: - virtual void registerToDumper(const std::string & id, - iohelper::Dumper & dumper) { + void registerToDumper(const std::string & id, + iohelper::Dumper & dumper) override { dumper.addElemDataField(id, *this); }; /// for connection to a FieldCompute - inline virtual Field * connect(FieldComputeProxy & proxy) { + inline Field * connect(FieldComputeProxy & proxy) override { return proxy.connectToField(this); } /// for connection to a Homogenizer - inline virtual ComputeFunctorInterface * connect(HomogenizerProxy & proxy) { + 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) { + 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_homogenizing_field.hh b/src/io/dumper/dumper_homogenizing_field.hh index ad50139dd..443468e72 100644 --- a/src/io/dumper/dumper_homogenizing_field.hh +++ b/src/io/dumper/dumper_homogenizing_field.hh @@ -1,217 +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 * * @brief description of field homogenizing field * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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)) + 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) { +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 */ /* ------------------------------------------------------------------------ */ typedef typename type::value_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 */ /* ------------------------------------------------------------------------ */ - virtual type func(const type & d, - __attribute__((unused)) Element global_index) { - + type func(const type & d, Element /*global_index*/) { 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() { return nb_data; }; - UInt getNbComponent(__attribute__((unused)) UInt old_nb_comp) { throw; }; + UInt getDim() override { return nb_data; }; + UInt getNbComponent(UInt /*old_nb_comp*/) { 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(){}; public: inline static ComputeFunctorInterface * createHomogenizer(Field & field); template <typename T> inline ComputeFunctorInterface * connectToField(T * field) { ElementTypeMap<UInt> nb_components = field->getNbComponents(); typedef typename T::types::return_type ret_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) { typedef dumper::AvgHomogenizingFunctor<ret_type> Homogenizer; Homogenizer * foo = new Homogenizer(nb_components); return foo; } template <> inline ComputeFunctorInterface * -HomogenizerProxy::instantiateHomogenizer<Vector<iohelper::ElemType> >( +HomogenizerProxy::instantiateHomogenizer<Vector<iohelper::ElemType>>( __attribute__((unused)) ElementTypeMap<UInt> & nb_components) { throw; - return NULL; + 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__ -} // akantu +} // namespace akantu #endif /* __AKANTU_DUMPER_HOMOGENIZING_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_material_padders.hh b/src/io/dumper/dumper_material_padders.hh index b19377c25..c5a0d1700 100644 --- a/src/io/dumper/dumper_material_padders.hh +++ b/src/io/dumper/dumper_material_padders.hh @@ -1,297 +1,298 @@ /** * @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 * * @brief Material padders for plane stress/ plane strain * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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) { + 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() { return 9; }; + UInt getDim() override { return 9; }; - UInt getNbComponent(__attribute__((unused)) UInt old_nb_comp) { + UInt getNbComponent(UInt /*old_nb_comp*/) { 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) { + 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() { return 9; }; + UInt getDim() override { return 9; }; - UInt getNbComponent(__attribute__((unused)) UInt old_nb_comp) { + UInt getNbComponent(UInt /*old_nb_comp*/) { 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, - __attribute__((unused)) Element global_element_id) { + inline Matrix<Real> func(const Vector<Real> & in, Element /*global_element_id*/) { 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() { return spatial_dimension * spatial_dimension; }; + UInt getDim() override { return spatial_dimension * spatial_dimension; }; - UInt getNbComponent(__attribute__((unused)) UInt old_nb_comp) { + UInt getNbComponent(UInt /*old_nb_comp*/) { 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, - __attribute__((unused)) Element global_element_id) { + Element /*global_element_id*/) { 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() { return spatial_dimension; }; + UInt getDim() override { return spatial_dimension; }; - UInt getNbComponent(__attribute__((unused)) UInt old_nb_comp) { + UInt getNbComponent(UInt /*old_nb_comp*/) { 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, - __attribute__((unused)) Element global_element_id) { + Element /*global_element_id*/) { 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() { return 1; }; + UInt getDim() override { return 1; }; - UInt getNbComponent(__attribute__((unused)) UInt old_nb_comp) { + UInt getNbComponent(UInt /*old_nb_comp*/) { 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 c462adc14..e01599dcf 100644 --- a/src/io/dumper/dumper_nodal_field.hh +++ b/src/io/dumper/dumper_nodal_field.hh @@ -1,240 +1,249 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ #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 = NULL) : + __attribute__((unused)) const UInt * filter = nullptr) + : - internal_it(vect), offset(offset), n(n), stride(stride) {} + 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); + }; - bool operator!=(const iterator & it) const { return internal_it != it.internal_it; } - iterator & operator++() { internal_it += offset; return *this; }; - Vector<T> operator* (){ 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 = NULL) : field(field), n(n), stride(stride), padding(0) { - AKANTU_DEBUG_ASSERT(filter == NULL, "Filter passed to unfiltered NodalField!"); + AKANTU_DEBUG_ASSERT(filter == nullptr, + "Filter passed to unfiltered NodalField!"); if(n == 0) { this->n = field.getNbComponent() - stride; } } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ - - virtual void registerToDumper(const std::string & id, - iohelper::Dumper & dumper) { + + 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() { return true; } - void checkHomogeneity() { this->homogeneous = true; } + 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 { + bool operator!=(const iterator & it) const override { return filter != it.filter; } - iterator & operator++() { + iterator & operator++() override { ++filter; return *this; } - Vector<T> operator* () { + 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 != NULL, - "No filter passed to filtered NodalField!"); + 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 */ /* ------------------------------------------------------------------------ */ - - virtual void registerToDumper(const std::string & id, iohelper::Dumper & dumper) { + + 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() { - return true; - } - void checkHomogeneity() { this->homogeneous = true; } + 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_paraview.hh b/src/io/dumper/dumper_paraview.hh index 448fd2ee3..eabc41a88 100644 --- a/src/io/dumper/dumper_paraview.hh +++ b/src/io/dumper/dumper_paraview.hh @@ -1,74 +1,74 @@ /** * @file dumper_paraview.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Sun Oct 19 2014 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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); - virtual ~DumperParaview(); + ~DumperParaview() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: // void dump(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: - void setBaseName(const std::string & basename); + void setBaseName(const std::string & basename) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; } // akantu #endif /* __AKANTU_DUMPER_PARAVIEW_HH__ */ diff --git a/src/io/mesh_io/mesh_io_abaqus.hh b/src/io/mesh_io/mesh_io_abaqus.hh index 877d87efc..0f6beec0a 100644 --- a/src/io/mesh_io/mesh_io_abaqus.hh +++ b/src/io/mesh_io/mesh_io_abaqus.hh @@ -1,60 +1,60 @@ /** * @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 * * @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) * * Akantu is free 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 "mesh_io.hh" #include "mesh_accessor.hh" #ifndef __AKANTU_MESH_IO_ABAQUS_HH__ #define __AKANTU_MESH_IO_ABAQUS_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ class MeshIOAbaqus : public MeshIO { public: MeshIOAbaqus(); - virtual ~MeshIOAbaqus(); + ~MeshIOAbaqus() override; /// read a mesh from the file - virtual void read(const std::string & filename, Mesh & mesh); + 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 bd32eed14..d2037f66c 100644 --- a/src/io/mesh_io/mesh_io_diana.cc +++ b/src/io/mesh_io/mesh_io_diana.cc @@ -1,604 +1,604 @@ /** * @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 * * @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) * * Akantu is free 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 <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); UInt * 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() {} /* -------------------------------------------------------------------------- */ 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_DEBUG_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_DEBUG_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); } std::stringstream * str = new std::stringstream(line); UInt id; std::string name; char c; *str >> id >> name >> c; Array<UInt> * 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); std::set<UInt>::iterator 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 = NULL; + Array<UInt> * connectivity = nullptr; UInt node_per_element = 0; Element elem; - UInt * read_order = NULL; + UInt * read_order = nullptr; while (1) { 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]; strcpy(tutu, line.c_str()); 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; typedef std::map<std::string, Real> MatProp; 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 (MatProp::iterator 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 (MatProp::iterator 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 7ddcbed5c..65004a5cc 100644 --- a/src/io/mesh_io/mesh_io_diana.hh +++ b/src/io/mesh_io/mesh_io_diana.hh @@ -1,107 +1,107 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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(); - virtual ~MeshIODiana(); + ~MeshIODiana() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// read a mesh from the file - virtual void read(const std::string & filename, Mesh & mesh); + 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); + 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 4fb0f54bc..c2b7287bf 100644 --- a/src/io/mesh_io/mesh_io_msh.cc +++ b/src/io/mesh_io/mesh_io_msh.cc @@ -1,971 +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 * * @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) * * Akantu is free 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/>. * */ /* ----------------------------------------------------------------------------- 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[_kirchhoff_shell] = _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() {} /* -------------------------------------------------------------------------- */ /* 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_DEBUG_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_DEBUG_ERROR("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_DEBUG_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 = NULL; + 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 143bd095e..7c905705b 100644 --- a/src/io/mesh_io/mesh_io_msh.hh +++ b/src/io/mesh_io/mesh_io_msh.hh @@ -1,115 +1,115 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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(); - virtual ~MeshIOMSH(); + ~MeshIOMSH() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// read a mesh from the file - virtual void read(const std::string & filename, Mesh & mesh); + 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); + 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/parser/cppargparse/cppargparse.cc b/src/io/parser/cppargparse/cppargparse.cc index f4a82dc00..acdc871a8 100644 --- a/src/io/parser/cppargparse/cppargparse.cc +++ b/src/io/parser/cppargparse/cppargparse.cc @@ -1,528 +1,531 @@ /** * @file cppargparse.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Apr 03 2014 * @date last modification: Wed Nov 11 2015 * * @brief implementation of the ArgumentParser * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "cppargparse.hh" #include <cstdlib> #include <cstring> #include <libgen.h> #include <iostream> #include <iomanip> #include <string> #include <queue> #include <sstream> #include <algorithm> #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() : external_exit(NULL), prank(0), psize(1) { +ArgumentParser::ArgumentParser() : external_exit(nullptr), prank(0), psize(1) { this->addArgument("-h;--help", "show this help message and exit", 0, _boolean, false, true); } /* -------------------------------------------------------------------------- */ ArgumentParser::~ArgumentParser() { for (_Arguments::iterator 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 { Arguments::const_iterator 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 (std::vector<std::string>::iterator 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); char *x = (char *)malloc(len+1); /* 1 for the null terminator */ - if(!x) return NULL; /* malloc could not allocate memory */ + 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; for (int i = 0; i < argc; ++i) { argvs.push_back(std::string(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 (PositionalArgument::iterator 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; ArgumentKeyMap::iterator key_it = key_args.find(arg); bool is_positional = false; - _Argument * argument_ptr = NULL; + _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; // "+" - // [[fallthrough]]; un-comment when compiler will get it + /* 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 (_Arguments::iterator 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 (Arguments::const_iterator 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 (_Arguments::const_iterator 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 (PositionalArgument::const_iterator 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; - // [[fallthrough]]; un-comment when compiler will get it + /* 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 (PositionalArgument::const_iterator 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 (_Arguments::const_iterator 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_tmpl.hh b/src/io/parser/cppargparse/cppargparse_tmpl.hh index 92a662404..d62452a05 100644 --- a/src/io/parser/cppargparse/cppargparse_tmpl.hh +++ b/src/io/parser/cppargparse/cppargparse_tmpl.hh @@ -1,245 +1,245 @@ /** * @file cppargparse_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Apr 03 2014 * @date last modification: Tue Dec 08 2015 * * @brief Implementation of the templated part of the commandline argument * parser * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <stdexcept> #include <sstream> #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()), nargs(1), type(_string), required(false), parsed(false), has_default(false), has_const(false), is_positional(false) {} - virtual ~_Argument() {} + ~_Argument() override {} void setValues(std::vector<std::string> & values) { for (std::vector<std::string>::iterator 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; ArgumentType type; bool required; bool parsed; bool has_default; bool has_const; std::vector<std::string> keys; bool is_positional; }; /* -------------------------------------------------------------------------- */ /// typed storage of the arguments template <class T> class ArgumentParser::ArgumentStorage : public ArgumentParser::_Argument { public: ArgumentStorage() : _default(T()), _const(T()), values(std::vector<T>()) {} - virtual void addValue(std::string & value) { + void addValue(std::string & value) override { std::stringstream sstr(value); T t; sstr >> t; values.push_back(t); } - virtual void setToDefault() { + void setToDefault() override { values.clear(); values.push_back(_default); } - virtual void setToConst() { + void setToConst() override { values.clear(); values.push_back(_const); } - void printself(std::ostream & stream) const { + void printself(std::ostream & stream) const override { stream << this->name << " ="; stream << std::boolalpha; // for boolean for (typename std::vector<T>::const_iterator vit = this->values.begin(); vit != this->values.end(); ++vit) { stream << " " << *vit; } } - virtual std::ostream & _printDefault(std::ostream & stream) const { + std::ostream & _printDefault(std::ostream & stream) const override { stream << _default; return stream; } - virtual std::ostream & _printConst(std::ostream & stream) const { + 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 ArgumentParser::ArgumentStorage<T> & _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 ArgumentParser::ArgumentStorage<T> & _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/parameter_registry.hh b/src/io/parser/parameter_registry.hh index 913b81f80..5db930cb4 100644 --- a/src/io/parser/parameter_registry.hh +++ b/src/io/parser/parameter_registry.hh @@ -1,217 +1,217 @@ /** * @file parameter_registry.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Aug 09 2012 * @date last modification: Thu Dec 17 2015 * * @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) * * Akantu is free 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 "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) { ParameterAccessType 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; }; /* -------------------------------------------------------------------------- */ /* 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); + void setAuto(const ParserParameter & param) override; T & getTyped(); const T & getTyped() const; - virtual void printself(std::ostream & stream) const; + void printself(std::ostream & stream) const override; - inline operator Real() const; + 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 typedef std::map<std::string, Parameter *> Parameters; Parameters params; /// list of sub-registries typedef std::map<std::string, ParameterRegistry *> SubRegisteries; SubRegisteries sub_registries; /// should accessor check in sub registries bool consisder_sub; }; } // akantu #include "parameter_registry_tmpl.hh" #endif /* __AKANTU_PARAMETER_REGISTRY_HH__ */ diff --git a/src/io/parser/parsable.hh b/src/io/parser/parsable.hh index 16dfab955..8911bddd2 100644 --- a/src/io/parser/parsable.hh +++ b/src/io/parser/parsable.hh @@ -1,76 +1,76 @@ /** * @file parameter_registry.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Aug 09 2012 * @date last modification: Thu Dec 17 2015 * * @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) * * Akantu is free 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 "aka_common.hh" #include "parser.hh" #include "parameter_registry.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 SectionType & section_type, const ID & id = std::string()); - virtual ~Parsable(); + ~Parsable() override; /// Add subsection to the sub_sections map void registerSubSection(const SectionType & 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: SectionType section_type; /// ID of parsable object ID pid; typedef std::pair<SectionType, std::string> SubSectionKey; typedef std::map<SubSectionKey, Parsable *> SubSections; /// Subsections map SubSections sub_sections; }; } // akantu #include "parsable_tmpl.hh" #endif /* __AKANTU_PARSABLE_HH__ */ diff --git a/src/io/parser/parser.hh b/src/io/parser/parser.hh index 93f74edf7..ffe397dcc 100644 --- a/src/io/parser/parser.hh +++ b/src/io/parser/parser.hh @@ -1,515 +1,515 @@ /** * @file parser.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 * @date last modification: Wed Jan 13 2016 * * @brief File parser interface * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 \ (global) \ (material) \ (model) \ (mesh) \ (heat) \ (contact) \ (friction) \ (embedded_interface) \ (rules) \ (non_local) \ (user) \ (solver) \ (neighborhoods) \ (neighborhood) \ (time_step_solver) \ (non_linear_solver) \ (model_solver) \ (integration_scheme) \ (weight_function) \ (not_defined) // clang-format on #define AKANTU_SECTION_TYPES_PREFIX(elem) BOOST_PP_CAT(_st_, elem) #define AKANTU_SECT_PREFIX(s, data, elem) AKANTU_SECTION_TYPES_PREFIX(elem) /// Defines the possible section types enum SectionType { BOOST_PP_SEQ_ENUM( BOOST_PP_SEQ_TRANSFORM(AKANTU_SECT_PREFIX, _, AKANTU_SECTION_TYPES)) }; #undef AKANTU_SECT_PREFIX #define AKANTU_SECTION_TYPE_PRINT_CASE(r, data, elem) \ case AKANTU_SECTION_TYPES_PREFIX(elem): { \ stream << BOOST_PP_STRINGIZE(AKANTU_SECTION_TYPES_PREFIX(elem)); \ break; \ } inline std::ostream & operator<<(std::ostream & stream, SectionType type) { switch (type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_SECTION_TYPE_PRINT_CASE, _, AKANTU_SECTION_TYPES) default: stream << "not a SectionType"; break; } return stream; } #undef AKANTU_SECTION_TYPE_PRINT_CASE /// 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() - : parent_section(NULL), name(std::string()), value(std::string()), + : parent_section(nullptr), 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) : parent_section(param.parent_section), name(param.name), value(param.value), dbg_filename(param.dbg_filename), dbg_line(param.dbg_line), dbg_column(param.dbg_column) {} virtual ~ParserParameter() {} /// 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; /// 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: typedef std::multimap<SectionType, ParserSection> SubSections; typedef std::map<std::string, ParserParameter> Parameters; private: typedef SubSections::const_iterator const_section_iterator_; public: /* ------------------------------------------------------------------------ */ /* SubSection iterator */ /* ------------------------------------------------------------------------ */ /// Iterator on sections class const_section_iterator { public: const_section_iterator() {} const_section_iterator(const const_section_iterator & other) : it(other.it) {} const_section_iterator(const const_section_iterator_ & it) : it(it) {} const_section_iterator & operator=(const const_section_iterator & other) { if (this != &other) { it = other.it; } return *this; } 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) : it(other.it) {} 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() - : parent_section(NULL), name(std::string()), type(_st_not_defined) {} + : parent_section(nullptr), name(std::string()), type(_st_not_defined) {} ParserSection(const std::string & name, SectionType type) - : parent_section(NULL), name(name), type(type) {} + : parent_section(nullptr), name(name), type(type) {} ParserSection(const std::string & name, SectionType 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() { Parameters::iterator pit = this->parameters.begin(); for (; pit != this->parameters.end(); ++pit) pit->second.setParent(*this); SubSections::iterator sit = this->sub_sections_by_type.begin(); for (; sit != this->sub_sections_by_type.end(); ++sit) sit->second.setParent(*this); } /* ---------------------------------------------------------------------- */ /* Accessors */ /* ---------------------------------------------------------------------- */ public: /// Get begin and end iterators on subsections of certain type std::pair<const_section_iterator, const_section_iterator> getSubSections(SectionType type = _st_not_defined) const { if (type != _st_not_defined) { std::pair<const_section_iterator_, const_section_iterator_> range = sub_sections_by_type.equal_range(type); return std::pair<const_section_iterator, const_section_iterator>( range.first, range.second); } else { return std::pair<const_section_iterator, const_section_iterator>( sub_sections_by_type.begin(), sub_sections_by_type.end()); } } /// Get number of subsections of certain type UInt getNbSubSections(SectionType type = _st_not_defined) const { if (type != _st_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 std::pair<const_parameter_iterator, const_parameter_iterator> 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 SectionType 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; /// Name of section std::string name; /// Type of section, see AKANTU_SECTION_TYPES SectionType type; /// 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", _st_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 #include "parser_tmpl.hh" #endif /* __AKANTU_PARSER_HH__ */ diff --git a/src/mesh/element_type_map.hh b/src/mesh/element_type_map.hh index 50ead8453..3a93260ad 100644 --- a/src/mesh/element_type_map.hh +++ b/src/mesh/element_type_map.hh @@ -1,437 +1,437 @@ /** * @file element_type_map.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 31 2011 * @date last modification: Fri Oct 02 2015 * * @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) * * Akantu is free 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 "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(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(); + ~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. */ inline Stored & operator()(const Stored & insert, const SupportType & type, const GhostType & ghost_type = _not_ghost); /// 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. */ typedef std::map<SupportType, Stored> DataMap; 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() {} 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; template <typename... pack> using named_argument_test = aka::conjunction<aka::bool_constant<(sizeof...(pack) > 0)>, is_named_argument<pack>...>; public: template <typename... pack> std::enable_if_t<named_argument_test<pack...>{}, ElementTypesIteratorHelper> elementTypes(pack &&... _pack) const { return elementTypesImpl(use_named_args, std::forward<decltype(_pack)>(_pack)...); } template <typename... pack> std::enable_if_t<not named_argument_test<pack...>{}, 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; /*! 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) const; /// access the data of an element, this combine the map and array accessor inline T & operator()(const Element & element); /* 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(); /*! 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 - virtual void printself(std::ostream & stream, int indent = 0) const; + 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/group_manager.cc b/src/mesh/group_manager.cc index 11ff31129..9899e747d 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 * * @brief Stores information about ElementGroup and NodeGroup * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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> /* -------------------------------------------------------------------------- */ 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_DEBUG_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(); NodeGroups::iterator nit = node_groups.find(group_name); NodeGroups::iterator 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 = NULL; + 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_DEBUG_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(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); std::set<UInt>::iterator it = global_clusters[c].begin(); std::set<UInt>::iterator 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 { + 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 { + 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) { + 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, 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, 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, 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); typedef typename ElementTypeMapArray<T>::type_iterator 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); std::map<std::string, UInt>::iterator 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)); } } } } std::set<std::string>::iterator git = group_names.begin(); std::set<std::string>::iterator 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 (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it) { it->second->printself(stream, indent + 1); node_group_seen.insert(it->second->getNodeGroup().getName()); } for (const_node_group_iterator 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(); ElementGroups::const_iterator it = element_groups.begin(); ElementGroups::const_iterator 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"); NodeGroups::const_iterator nnames_it = node_groups.begin(); NodeGroups::const_iterator 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"); ElementGroups::const_iterator gnames_it = this->element_groups.begin(); ElementGroups::const_iterator 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 { const_element_group_iterator 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) { element_group_iterator 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 { const_node_group_iterator 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) { node_group_iterator 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_inline_impl.cc b/src/mesh/group_manager_inline_impl.cc index d6ebfbbf2..72f4946ff 100644 --- a/src/mesh/group_manager_inline_impl.cc +++ b/src/mesh/group_manager_inline_impl.cc @@ -1,207 +1,207 @@ /** * @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 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "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 == NULL) - return NULL; + 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 == NULL) - return NULL; + 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 == NULL) - return NULL; + 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, ElementTypeMap<UInt> nb_data_per_elem) { const field_type * field_ptr = &field; - if (field_ptr == NULL) - return NULL; + 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 == NULL) - return NULL; + if (field_ptr == nullptr) + return nullptr; if (group_name == "all") throw; typedef typename field_type::type T; ElementGroup & group = this->getElementGroup(group_name); UInt dim = group.getDimension(); if (dim != spatial_dimension) throw; const ElementTypeMapArray<UInt> & elemental_filter = group.getElements(); ElementTypeMapArrayFilter<T> * 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 == NULL) - return NULL; + if (field == nullptr) + return nullptr; if (group_name == "all") { typedef typename dumper::NodalField<type, false> DumpType; - DumpType * dumper = new DumpType(*field, 0, 0, NULL); + DumpType * 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()); typedef typename dumper::NodalField<type, true> DumpType; DumpType * dumper = new DumpType(*field, 0, 0, nodal_filter); dumper->setPadding(padding_size); return dumper; } - return NULL; + 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 NULL; + return nullptr; if (group_name == "all") { typedef typename dumper::NodalField<type, false> DumpType; DumpType * 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()); typedef typename dumper::NodalField<type, true> DumpType; DumpType * dumper = new DumpType(*field, size, stride, nodal_filter); dumper->setPadding(padding_size); return dumper; } - return NULL; + return nullptr; } /* -------------------------------------------------------------------------- */ } // akantu #endif diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc index a75f9b14a..a1c460a24 100644 --- a/src/mesh/mesh.cc +++ b/src/mesh/mesh.cc @@ -1,472 +1,476 @@ /** * @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 * * @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) * * Akantu is free 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 <sstream> - #include "aka_config.hh" - /* -------------------------------------------------------------------------- */ #include "element_class.hh" #include "group_manager_inline_impl.cc" #include "mesh.hh" #include "mesh_io.hh" +#include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "facet_synchronizer.hh" #include "mesh_utils_distribution.hh" #include "node_synchronizer.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumper_field.hh" #include "dumper_internal_material_field.hh" #endif /* -------------------------------------------------------------------------- */ +#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, 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(); } /* -------------------------------------------------------------------------- */ 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()); } } 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(_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_DEBUG_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 ffaa08a3b..a22dea521 100644 --- a/src/mesh/mesh.hh +++ b/src/mesh/mesh.hh @@ -1,602 +1,602 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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} Mesh::type_iterator it = mesh.firstType(dim, ghost_type); Mesh::type_iterator end = mesh.lastType(dim, ghost_type); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); const Array<UInt> & conn = mesh.getConnectivity(*it); for(UInt e = 0; e < nb_element; ++e) { ... } } @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, std::shared_ptr<Array<Real>> nodes, const ID & id = "mesh", const MemoryID & memory_id = 0); - virtual ~Mesh(); + ~Mesh() override; /// @typedef ConnectivityTypeList list of the types present in a Mesh typedef std::set<ElementType> ConnectivityTypeList; /// 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 - virtual void printself(std::ostream & stream, int indent = 0) const; + 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); /// convert a element to a linearized element inline UInt elementToLinearized(const Element & elem) const; /// convert a linearized element to an element inline Element linearizedToElement(UInt linearized_element) const; /// update the types offsets array for the conversions // inline void updateTypesOffsets(const GhostType & ghost_type); /// 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 inline void getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type = _not_ghost) const; inline void getBarycenter(const Element & element, Vector<Real> & barycenter) const; /// get the element connected to a subelement const Array<std::vector<Element>> & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the element connected to a subelement Array<std::vector<Element>> & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get the subelement connected to an element const Array<Element> & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the subelement connected to an element Array<Element> & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// 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); /// 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); /// get local connectivity of a facet for a given facet type static inline MatrixProxy<UInt> getFacetLocalConnectivity(const ElementType & type, UInt t = 0); /// get connectivity of facets for a given element inline Matrix<UInt> getFacetConnectivity(const Element & element, UInt t = 0) const; /// 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); /// get the type of the surface element associated to a given element static inline ElementType getFacetType(const ElementType & type, UInt t = 0); /// get all the type of the surface element associated to a given element static inline VectorProxy<ElementType> getAllFacetTypes(const ElementType & type); /// 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 // &); AKANTU_GET_MACRO(Communicator, *communicator, const auto &); /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshAccessor; //#if defined(AKANTU_COHESIVE_ELEMENT) // friend class CohesiveElementInserter; //#endif //#if defined(AKANTU_IGFEM) // template <UInt dim> friend class MeshIgfemSphericalGrowingGel; //#endif 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 const 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_data.hh b/src/mesh/mesh_data.hh index 92f634eb6..41f2e445c 100644 --- a/src/mesh/mesh_data.hh +++ b/src/mesh/mesh_data.hh @@ -1,150 +1,150 @@ /** * @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 * * @brief Stores generic data loaded from the mesh file * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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: typedef MeshDataTypeCode TypeCode; typedef std::map<std::string, ElementTypeMapBase *> ElementalDataMap; typedef std::vector<std::string> StringVector; typedef std::map<std::string, TypeCode> TypeCodeMap; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshData(const ID & id = "mesh_data", const ID & parent_id = "", const MemoryID & memory_id = 0); - ~MeshData(); + ~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); /// Get an existing elemental data array template <typename T> bool hasDataArray(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) 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_events.hh b/src/mesh/mesh_events.hh index bb0cb2539..77dc78da3 100644 --- a/src/mesh/mesh_events.hh +++ b/src/mesh/mesh_events.hh @@ -1,187 +1,187 @@ /** * @file mesh_events.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Feb 20 2015 * @date last modification: Mon Dec 07 2015 * * @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) * * Akantu is free 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 "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() {} /// 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: - virtual ~NewNodesEvent(){}; + ~NewNodesEvent() override{}; }; /// akantu::MeshEvent related to nodes removed from the mesh class RemovedNodesEvent : public MeshEvent<UInt> { public: - virtual ~RemovedNodesEvent(){}; + ~RemovedNodesEvent() override{}; 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: - virtual ~NewElementsEvent(){}; + ~NewElementsEvent() override{}; }; /// akantu::MeshEvent related to elements removed from the mesh class RemovedElementsEvent : public MeshEvent<Element> { public: - virtual ~RemovedElementsEvent(){}; + ~RemovedElementsEvent() override{}; inline RemovedElementsEvent(const Mesh & mesh, 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: - virtual ~ChangedElementsEvent(){}; + ~ChangedElementsEvent() override{}; inline ChangedElementsEvent( const Mesh & mesh, ID new_numbering_id = "changed_event:new_numbering") : RemovedElementsEvent(mesh, 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(){}; /* ------------------------------------------------------------------------ */ /* 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) = 0; /// function to implement to react on akantu::RemovedNodesEvent virtual void onNodesRemoved(const Array<UInt> & nodes_list, const Array<UInt> & new_numbering, const RemovedNodesEvent & event) = 0; /// function to implement to react on akantu::NewElementsEvent virtual void onElementsAdded(const Array<Element> & elements_list, const NewElementsEvent & event) = 0; /// function to implement to react on akantu::RemovedElementsEvent virtual void onElementsRemoved(const Array<Element> & elements_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) = 0; /// 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) = 0; }; } // akantu #endif /* __AKANTU_MESH_EVENTS_HH__ */ diff --git a/src/mesh/mesh_inline_impl.cc b/src/mesh/mesh_inline_impl.cc index a506bee50..df8fe3c66 100644 --- a/src/mesh/mesh_inline_impl.cc +++ b/src/mesh/mesh_inline_impl.cc @@ -1,635 +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 * * @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) * * Akantu is free 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 "aka_iterators.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) #include "cohesive_element.hh" #endif /* -------------------------------------------------------------------------- */ #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, 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 Array<std::vector<Element>> & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) const { return getData<std::vector<Element>>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array<std::vector<Element>> & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) { return getData<std::vector<Element>>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline const Array<Element> & Mesh::getSubelementToElement(const ElementType & type, const GhostType & ghost_type) const { return getData<Element>("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array<Element> & 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); } /* -------------------------------------------------------------------------- */ 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); Real * 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 ElementType Mesh::getFacetType(const ElementType & type, UInt t) { ElementType surface_type = _not_defined; #define GET_FACET_TYPE(type) surface_type = ElementClass<type>::getFacetType(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_TYPE); #undef GET_FACET_TYPE return surface_type; } /* -------------------------------------------------------------------------- */ inline VectorProxy<ElementType> Mesh::getAllFacetTypes(const ElementType & type) { #define GET_FACET_TYPE(type) \ UInt nb = ElementClass<type>::getNbFacetTypes(); \ ElementType * elt_ptr = \ const_cast<ElementType *>(ElementClass<type>::getFacetTypeInternal()); \ return VectorProxy<ElementType>(elt_ptr, nb); AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_TYPE); #undef GET_FACET_TYPE } /* -------------------------------------------------------------------------- */ 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 MatrixProxy<UInt> 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 MatrixProxy<UInt>( nullptr, 0, 0); // This avoid a compilation warning but will certainly // also cause a segfault if reached } /* -------------------------------------------------------------------------- */ inline Matrix<UInt> Mesh::getFacetConnectivity(const Element & element, UInt t) const { AKANTU_DEBUG_IN(); Matrix<UInt> local_facets(getFacetLocalConnectivity(element.type, t), false); 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 != NULL, "The global ids are note set."); + 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_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_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_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/node_group.hh b/src/mesh/node_group.hh index 1003698b6..b8362db4f 100644 --- a/src/mesh/node_group.hh +++ b/src/mesh/node_group.hh @@ -1,141 +1,141 @@ /** * @file node_group.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Dec 08 2015 * * @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) * * Akantu is free 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 "aka_common.hh" #include "aka_array.hh" #include "aka_memory.hh" #include "mesh_filter.hh" #include "dumpable.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); - virtual ~NodeGroup(); + ~NodeGroup() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: typedef Array<UInt>::const_iterator<UInt> const_node_iterator; /// 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); inline decltype(auto) find(UInt node) const { return node_group.find(node); } /// 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_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc index 65ef1d158..e328de401 100644 --- a/src/mesh_utils/cohesive_element_inserter.cc +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -1,451 +1,449 @@ /** * @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 * * @brief Cohesive element inserter functions * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "element_group.hh" //#include "facet_synchronizer.hh" #include "global_ids_updater.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <limits> /* -------------------------------------------------------------------------- */ namespace akantu { CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, bool is_extrinsic, const ID & id) : id(id), mesh(mesh), mesh_facets(mesh.initMeshFacets()), insertion_facets("insertion_facets", id), insertion_limits(mesh.getSpatialDimension(), 2), check_facets("check_facets", id) { - - MeshUtils::buildAllFacets(mesh, mesh_facets, 0); init(is_extrinsic); } /* -------------------------------------------------------------------------- */ CohesiveElementInserter::~CohesiveElementInserter() { #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) delete global_ids_updater; #endif } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::init(bool is_extrinsic) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); MeshUtils::resetFacetToDouble(mesh_facets); /// initialize facet insertion array insertion_facets.initialize(mesh_facets, _spatial_dimension = (spatial_dimension - 1), _with_nb_element = true); // mesh_facets.initElementTypeMapArray( // insertion_facets, 1, spatial_dimension - 1, false, _ek_regular, true); /// init insertion limits for (UInt dim = 0; dim < spatial_dimension; ++dim) { insertion_limits(dim, 0) = std::numeric_limits<Real>::max() * (-1.); insertion_limits(dim, 1) = std::numeric_limits<Real>::max(); } if (is_extrinsic) { check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(check_facets, 1, spatial_dimension - // 1); initFacetsCheck(); } #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) facet_synchronizer = NULL; global_ids_updater = NULL; #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::initFacetsCheck() { 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 facet_gt = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); for (; it != last; ++it) { ElementType facet_type = *it; Array<bool> & f_check = check_facets(facet_type, facet_gt); const Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(facet_type, facet_gt); UInt nb_facet = element_to_facet.size(); f_check.resize(nb_facet); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull || (element_to_facet(f)[0].ghost_type == _ghost && element_to_facet(f)[1].ghost_type == _ghost)) { f_check(f) = false; } else f_check(f) = true; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector<Real> bary_facet(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for (; it != end; ++it) { ElementType type = *it; Array<bool> & f_check = check_facets(type, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (f_check(f)) { mesh_facets.getBarycenter(f, type, bary_facet.storage(), ghost_type); 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) f_check(f) = false; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ 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() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector<Real> bary_facet(spatial_dimension); for (auto && ghost_type : ghost_types) { for (const auto & type_facet : mesh_facets.elementTypes(spatial_dimension - 1, ghost_type)) { auto & f_insertion = insertion_facets(type_facet, ghost_type); auto & element_to_facet = mesh_facets.getElementToSubelement(type_facet, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type_facet, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull) continue; mesh_facets.getBarycenter(f, type_facet, bary_facet.storage(), ghost_type); 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) f_insertion(f) = true; } } } AKANTU_DEBUG_OUT(); return insertElements(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::insertIntrinsicElements(std::string physname, UInt material_index) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray<UInt> * phys_data; try { phys_data = &(mesh_facets.getData<UInt>("physical_names")); } catch (...) { phys_data = &(mesh_facets.registerData<UInt>("physical_names")); phys_data->initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true); // mesh_facets.initElementTypeMapArray(*phys_data, 1, spatial_dimension - 1, // false, _ek_regular, true); } Vector<Real> bary_facet(spatial_dimension); mesh_facets.createElementGroup(physname); GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for (; it != end; ++it) { const ElementType type_facet = *it; Array<bool> & f_insertion = insertion_facets(type_facet, ghost_type); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type_facet, ghost_type); UInt coord_in_limit = 0; ElementGroup & group = mesh.getElementGroup(physname); ElementGroup & group_facet = mesh_facets.getElementGroup(physname); Vector<Real> bary_physgroup(spatial_dimension); Real norm_bary; for (ElementGroup::const_element_iterator el_it( group.begin(type_facet, ghost_type)); el_it != group.end(type_facet, ghost_type); ++el_it) { UInt e = *el_it; mesh.getBarycenter(e, type_facet, bary_physgroup.storage(), ghost_type); #ifndef AKANTU_NDEBUG bool find_a_partner = false; #endif norm_bary = bary_physgroup.norm(); Array<UInt> & material_id = (*phys_data)(type_facet, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull) continue; mesh_facets.getBarycenter(f, type_facet, bary_facet.storage(), ghost_type); coord_in_limit = 0; while (coord_in_limit < spatial_dimension && (std::abs(bary_facet(coord_in_limit) - bary_physgroup(coord_in_limit)) / norm_bary < Math::getTolerance())) ++coord_in_limit; if (coord_in_limit == spatial_dimension) { f_insertion(f) = true; #ifndef AKANTU_NDEBUG find_a_partner = true; #endif group_facet.add(type_facet, f, ghost_type, false); material_id(f) = material_index; break; } } AKANTU_DEBUG_ASSERT(find_a_partner, "The element nO " << e << " of physical group " << physname << " did not find its associated facet!" << " Try to decrease math tolerance. " << std::endl); } } 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 defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) 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, _so_sum); } #endif 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 defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) if (mesh.isDistributed()) { /// update global ids this->synchronizeGlobalIDs(node_event); } #endif return nb_new_elements; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::updateInsertionFacets() { 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 facet_gt = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); for (; it != last; ++it) { ElementType facet_type = *it; Array<bool> & ins_facets = insertion_facets(facet_type, facet_gt); // this is the extrinsic case if (check_facets.exists(facet_type, facet_gt)) { Array<bool> & f_check = check_facets(facet_type, facet_gt); UInt nb_facets = f_check.size(); for (UInt f = 0; f < ins_facets.size(); ++f) { if (ins_facets(f)) { ++nb_facets; ins_facets(f) = false; f_check(f) = false; } } f_check.resize(nb_facets); } // and this the intrinsic one else { ins_facets.resize(mesh_facets.getNbElement(facet_type, facet_gt)); ins_facets.set(false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "CohesiveElementInserter [" << std::endl; stream << space << " + mesh [" << std::endl; mesh.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + mesh_facets [" << std::endl; mesh_facets.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } } // namespace akantu diff --git a/src/mesh_utils/cohesive_element_inserter.hh b/src/mesh_utils/cohesive_element_inserter.hh index decc1fc45..f220d71f9 100644 --- a/src/mesh_utils/cohesive_element_inserter.hh +++ b/src/mesh_utils/cohesive_element_inserter.hh @@ -1,204 +1,204 @@ /** * @file cohesive_element_inserter.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 * @date last modification: Fri Oct 02 2015 * * @brief Cohesive element inserter * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "mesh_utils.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> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: CohesiveElementInserter(Mesh & mesh, bool is_extrinsic = false, const ID & id = "cohesive_element_inserter"); - virtual ~CohesiveElementInserter(); + ~CohesiveElementInserter() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// init function void init(bool is_extrinsic); /// 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(); /// preset insertion of intrinsic cohesive elements along /// a predefined group of facet and assign them a defined material index. /// insertElement() method has to be called to finalize insertion. void insertIntrinsicElements(std::string physname, UInt material_index); /// insert extrinsic cohesive elements (returns the number of new /// cohesive elements) UInt insertElements(bool only_double_facets = false); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// limit check facets to match given insertion limits void limitCheckFacets(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) /// init parallel variables void initParallel(FacetSynchronizer * facet_synchronizer, ElementSynchronizer * element_synchronizer); #endif protected: /// init facets check void initFacetsCheck(); /// 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_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 &); /* ------------------------------------------------------------------------ */ /* 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 Array<Real> insertion_limits; /// vector containing facets in which extrinsic cohesive elements can be /// inserted ElementTypeMapArray<bool> check_facets; // /// facet synchronizer // FacetSynchronizer & facet_synchronizer; /// global connectivity ids updater std::unique_ptr<GlobalIdsUpdater> global_ids_updater; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const CohesiveElementInserter & _this) { _this.printself(stream); return stream; } class CohesiveNewNodesEvent : public NewNodesEvent{ public: CohesiveNewNodesEvent() = default; - virtual ~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 350049797..0837a19ec 100644 --- a/src/mesh_utils/cohesive_element_inserter_inline_impl.cc +++ b/src/mesh_utils/cohesive_element_inserter_inline_impl.cc @@ -1,106 +1,106 @@ /** * @file cohesive_element_inserter_inline_impl.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Cohesive element inserter inline functions * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #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(); ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; ElementTypeMapArray<UInt> & physical_names = mesh_facets.registerData<UInt>("physical_names"); - Array<bool> * vect = NULL; - Array<unsigned int> * vect2 = NULL; + Array<bool> * vect = nullptr; + Array<unsigned int> * vect2 = nullptr; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> 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; 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/global_ids_updater.hh b/src/mesh_utils/global_ids_updater.hh index 6cbe5e79e..eadc66eb0 100644 --- a/src/mesh_utils/global_ids_updater.hh +++ b/src/mesh_utils/global_ids_updater.hh @@ -1,100 +1,100 @@ /** * @file global_ids_updater.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Oct 02 2015 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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 virtual UInt getNbData(const Array<Element> & elements, - const SynchronizationTag & tag) const; + inline UInt getNbData(const Array<Element> & elements, + const SynchronizationTag & tag) const override; - inline virtual void packData(CommunicationBuffer & buffer, - const Array<Element> & elements, - const SynchronizationTag & tag) const; + inline void packData(CommunicationBuffer & buffer, + const Array<Element> & elements, + const SynchronizationTag & tag) const override; - inline virtual void unpackData(CommunicationBuffer & buffer, - const Array<Element> & elements, - const SynchronizationTag & tag); + 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/mesh_partition.hh b/src/mesh_utils/mesh_partition.hh index 7f834ce03..cb2caacb3 100644 --- a/src/mesh_utils/mesh_partition.hh +++ b/src/mesh_utils/mesh_partition.hh @@ -1,151 +1,151 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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); - virtual ~MeshPartition(); + ~MeshPartition() override; class EdgeLoadFunctor { public: virtual Int operator()(const Element & el1, const Element & el2) const noexcept = 0; }; class ConstEdgeLoadFunctor : public EdgeLoadFunctor { public: - virtual inline Int operator()(const Element &, const Element &) const - noexcept { + 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); /* ------------------------------------------------------------------------ */ /* 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; Array<Element> lin_to_element; }; } // 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.hh b/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.hh index bfb340547..a8f44b91a 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.hh +++ b/src/mesh_utils/mesh_partition/mesh_partition_mesh_data.hh @@ -1,98 +1,98 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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; - virtual void partitionate(UInt nb_part, - const EdgeLoadFunctor & edge_load_func = ConstEdgeLoadFunctor(), - const Array<UInt> & pairs = Array<UInt>()); - - virtual void reorder(); + 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.hh b/src/mesh_utils/mesh_partition/mesh_partition_scotch.hh index 81eb819b3..e96865878 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_scotch.hh +++ b/src/mesh_utils/mesh_partition/mesh_partition_scotch.hh @@ -1,81 +1,81 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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; - virtual void partitionate(UInt nb_part, - const EdgeLoadFunctor & edge_load_func = ConstEdgeLoadFunctor(), - const Array<UInt> & pairs = Array<UInt>()); - - virtual void reorder(); + 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 7ee541f65..d4378f2b7 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2172 +1,2172 @@ /** * @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 * * @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) * * Akantu is free 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 "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 (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); for (; first != last; ++first) { ElementType type = *first; UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator<Vector<UInt>> conn_it = mesh.getConnectivity(type, *gt).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 (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); e.ghost_type = *gt; for (; first != last; ++first) { ElementType type = *first; e.type = type; UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator<Vector<UInt>> conn_it = mesh.getConnectivity(type, *gt).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(); } /* -------------------------------------------------------------------------- */ /** * This function should disappear in the future (used in mesh partitioning) */ // void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<UInt> & // node_to_elem, // UInt spatial_dimension) { // AKANTU_DEBUG_IN(); // if (spatial_dimension == _all_dimensions) // spatial_dimension = mesh.getSpatialDimension(); // UInt nb_nodes = mesh.getNbNodes(); // const Mesh::ConnectivityTypeList & type_list = // mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator // it; // UInt nb_types = type_list.size(); // UInt nb_good_types = 0; // Vector<UInt> nb_nodes_per_element(nb_types); // UInt ** conn_val = new UInt *[nb_types]; // Vector<UInt> nb_element(nb_types); // for (it = type_list.begin(); it != type_list.end(); ++it) { // ElementType type = *it; // if (Mesh::getSpatialDimension(type) != spatial_dimension) // continue; // nb_nodes_per_element[nb_good_types] = Mesh::getNbNodesPerElement(type); // conn_val[nb_good_types] = mesh.getConnectivity(type, // _not_ghost).storage(); nb_element[nb_good_types] = // mesh.getConnectivity(type, _not_ghost).size(); // nb_good_types++; // } // AKANTU_DEBUG_ASSERT( // nb_good_types != 0, // "Some elements must be found in right dimension to compute facets!"); // /// 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 t = 0; t < nb_good_types; ++t) { // for (UInt el = 0; el < nb_element[t]; ++el) { // UInt el_offset = el * nb_nodes_per_element[t]; // for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) { // ++node_to_elem.rowOffset(conn_val[t][el_offset + n]); // } // } // } // node_to_elem.countToCSR(); // node_to_elem.resizeCols(); // node_to_elem.beginInsertions(); // /// rearrange element to get the node-element list // for (UInt t = 0, linearized_el = 0; t < nb_good_types; ++t) // for (UInt el = 0; el < nb_element[t]; ++el, ++linearized_el) { // UInt el_offset = el * nb_nodes_per_element[t]; // for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) // node_to_elem.insertInRow(conn_val[t][el_offset + n], linearized_el); // } // node_to_elem.endInsertions(); // delete[] conn_val; // 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 Array<Real>::const_vector_iterator 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); Vector<ElementType> facet_types = mesh.getAllFacetTypes(type); for (auto && ft : arange(facet_types.size())) { ElementType 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); const Matrix<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; std::map<UInt, UInt>::iterator 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) { GhostType 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)); std::map<UInt, UInt>::iterator it = renumbering_map.begin(); std::map<UInt, UInt>::iterator 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 = NULL; + 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 = NULL; + 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) { GhostType 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 = NULL; - Array<UInt> * sf_to_double = NULL; - Array<std::vector<Element>> * sf_to_subfacet_double = NULL; - Array<std::vector<Element>> * f_to_subfacet_double = NULL; - Array<std::vector<Element>> * el_to_subfacet_double = NULL; + 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 = NULL; + 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 = NULL; + 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 = NULL; - Array<std::vector<Element>> * f_to_subfacet_double = NULL; + 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 = NULL; + 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 = NULL; + 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 = NULL; + 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 = NULL; + 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, _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); UInt * conn_tmp_pointer = new UInt[nb_nodes_per_facet]; Vector<UInt> conn_tmp(conn_tmp_pointer, nb_nodes_per_facet); Element el_tmp; Element * 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 = NULL; - const Array<UInt> * sf_connectivity = NULL; - const Array<Element> * facet_to_element = NULL; - const Array<Element> * subfacet_to_facet = NULL; + 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 = NULL; + const Array<std::vector<Element>> * element_to_facet = nullptr; - const Element * opposing_el = NULL; + 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 = NULL; + Array<UInt> * conn_elem = nullptr; #if defined(AKANTU_COHESIVE_ELEMENT) - const Array<Element> * cohesive_facets = NULL; + const Array<Element> * cohesive_facets = nullptr; #endif UInt nb_nodes_per_element = 0; - UInt * n_update = NULL; + 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 != NULL, + 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 b7ed40928..4d9ff8267 100644 --- a/src/mesh_utils/mesh_utils.hh +++ b/src/mesh_utils/mesh_utils.hh @@ -1,244 +1,244 @@ /** * @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 * * @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) * * Akantu is free 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 "aka_common.hh" #include "mesh.hh" #include "aka_csr.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<Surface, Surface> & 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 = NULL); + 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/model/boundary_condition.hh b/src/model/boundary_condition.hh index ed18419b2..65a09e0a1 100644 --- a/src/model/boundary_condition.hh +++ b/src/model/boundary_condition.hh @@ -1,106 +1,108 @@ /** * @file boundary_condition.hh * * @author Dana Christen <dana.christen@gmail.com> * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Dec 18 2015 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_HH__ #define __AKANTU_BOUNDARY_CONDITION_HH__ #include "aka_common.hh" #include "boundary_condition_functor.hh" #include "mesh.hh" #include "fe_engine.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ namespace akantu { template <class ModelType> class BoundaryCondition { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ private: /* ------------------------------------------------------------------------ */ /* Constructors / Destructors / Initializers */ /* ------------------------------------------------------------------------ */ public: - BoundaryCondition() : model(NULL), primal(NULL), dual(NULL), primal_increment(NULL) {} + BoundaryCondition() + : model(nullptr), primal(nullptr), dual(nullptr), + primal_increment(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; Array<Real> * dual; Array<Real> * primal_increment; }; } // 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 cbc7358d8..776fa1514 100644 --- a/src/model/boundary_condition_functor.hh +++ b/src/model/boundary_condition_functor.hh @@ -1,197 +1,197 @@ /** * @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 * * @brief Definitions of the functors to apply boundary conditions * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 { typedef ::akantu::SpacialDirection Axis; struct Functor { enum Type { _dirichlet, _neumann }; }; /* ------------------------------------------------------------------------ */ /* Dirichlet */ /* ------------------------------------------------------------------------ */ namespace Dirichlet { /* ---------------------------------------------------------------------- */ class DirichletFunctor : public Functor { protected: DirichletFunctor() : axis(_x) {} 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_DEBUG_TO_IMPLEMENT(); } public: static const Type type = _dirichlet; protected: Axis axis; }; /* ---------------------------------------------------------------------- */ 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; }; } // end namespace Dirichlet /* ------------------------------------------------------------------------ */ /* Neumann */ /* ------------------------------------------------------------------------ */ namespace Neumann { /* ---------------------------------------------------------------------- */ class NeumannFunctor : public Functor { protected: NeumannFunctor() {} public: virtual void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const = 0; virtual ~NeumannFunctor() {} public: static const Type type = _neumann; }; /* ---------------------------------------------------------------------- */ class FromHigherDim : public NeumannFunctor { public: explicit FromHigherDim(const Matrix<Real> & mat) : bc_data(mat) {} - virtual ~FromHigherDim() {} + ~FromHigherDim() override {} public: inline void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, - const Vector<Real> & normals) const; + 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) {} - virtual ~FromSameDim() {} + ~FromSameDim() override {} public: inline void operator()(const IntegrationPoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, - const Vector<Real> & normals) const; + 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; + 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/common/neighborhood_base.hh b/src/model/common/neighborhood_base.hh index 73e5fcb22..b6f365edc 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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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); - virtual ~NeighborhoodBase(); + ~NeighborhoodBase() override; typedef std::vector<std::pair<IntegrationPoint, IntegrationPoint>> PairList; /* ------------------------------------------------------------------------ */ /* 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/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh index 3ea9e3e94..67b7f51c9 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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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); - virtual ~NeighborhoodMaxCriterion(); + ~NeighborhoodMaxCriterion() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the neighborhood - virtual void initNeighborhood(); + void initNeighborhood() override; /// create grid synchronizer and exchange ghost cells - virtual void createGridSynchronizer(); + 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/non_local_toolbox/base_weight_function.hh b/src/model/common/non_local_toolbox/base_weight_function.hh index 47252eec9..59bc32172 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 * * @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) * * Akantu is free 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 "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(_st_weight_function, "weight_function:" + type), manager(manager), type(type), spatial_dimension(manager.getModel().getMesh().getSpatialDimension()) { this->registerParam("update_rate", update_rate, 1U, _pat_parsmod, "Update frequency"); } - virtual ~BaseWeightFunction() {} + ~BaseWeightFunction() override {} /* ------------------------------------------------------------------------ */ /* 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/non_local_manager.hh b/src/model/common/non_local_toolbox/non_local_manager.hh index 458182e59..f249eac9c 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.hh +++ b/src/model/common/non_local_toolbox/non_local_manager.hh @@ -1,288 +1,288 @@ /** * @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 * * @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) * * Akantu is free 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 "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); - virtual ~NonLocalManager(); + ~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_neighborhood.hh b/src/model/common/non_local_toolbox/non_local_neighborhood.hh index e8f134948..b92eb3e3c 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood.hh @@ -1,135 +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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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); - virtual ~NonLocalNeighborhood(); + ~NonLocalNeighborhood() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// compute the weights for non-local averaging - void computeWeights(); + 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(); + 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.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh index 185a3ae6a..547766016 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,130 +1,130 @@ /** * @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 * * @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) * * Akantu is free 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 "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); - virtual ~NonLocalNeighborhoodBase(); + ~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_DEBUG_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_tmpl.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh index 780c3e002..aa4f9a31d 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,280 +1,280 @@ /** * @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 * * @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) * * Akantu is free 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 "non_local_manager.hh" #include "non_local_neighborhood.hh" #include "communicator.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(_st_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 PairList::const_iterator first_pair = pair_list[ghost_type].begin(); PairList::const_iterator last_pair = pair_list[ghost_type].end(); Array<Real>::vector_iterator 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 Array<Real>::const_vector_iterator 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]; Array<Real>::const_vector_iterator 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, [this, &quadrature_points_volumes]( + 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) { GhostType 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]); Array<Real>::const_vector_iterator 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 4a33ef9ea..c7db77db8 100644 --- a/src/model/dof_manager.cc +++ b/src/model/dof_manager.cc @@ -1,595 +1,595 @@ /** * @file dof_manager.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Aug 12 09:52:30 2015 * * @brief Implementation of the common parts of the DOFManagers * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager.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 "communicator.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #include <memory> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ DOFManager::DOFManager(const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), mesh(nullptr), local_system_size(0), pure_local_system_size(0), system_size(0), 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_DEBUG_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 = NULL; + 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 != NULL) { + 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 != NULL) + 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(); } /* -------------------------------------------------------------------------- */ DOFManager::DOFData::DOFData(const ID & dof_id) - : support_type(_dst_generic), group_support("__mesh__"), dof(NULL), - blocked_dofs(NULL), increment(NULL), previous(NULL), + : 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() {} /* -------------------------------------------------------------------------- */ DOFManager::DOFData & DOFManager::getNewDOFData(const ID & dof_id) { DOFStorage::iterator 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 = NULL; + 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 != NULL) { + 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 != NULL) { + 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, NULL); + derivatives.resize(order, nullptr); } else { - if (derivatives[order - 1] != NULL) { + 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 != NULL) { + 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() { DOFStorage::iterator it = this->dofs.begin(); DOFStorage::iterator 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; SparseMatricesMap::const_iterator 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; 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); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasLumpedMatrix(const ID & id) const { ID mtx_id = this->id + ":lumped_mtx:" + id; LumpedMatricesMap::const_iterator 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; NonLinearSolversMap::const_iterator 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; TimeStepSolversMap::const_iterator 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 23b76fc4c..fd22976d7 100644 --- a/src/model/dof_manager.hh +++ b/src/model/dof_manager.hh @@ -1,465 +1,463 @@ /** * @file dof_manager.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Jul 22 11:43:43 2015 * * @brief Class handling the different types of dofs * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #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); - virtual ~DOFManager(); + ~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 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 &); /* ------------------------------------------------------------------------ */ /* 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 - virtual void onNodesAdded(const Array<UInt> & nodes_list, - const NewNodesEvent & event); + void onNodesAdded(const Array<UInt> & nodes_list, + const NewNodesEvent & event) override; /// function to implement to react on akantu::RemovedNodesEvent - virtual void onNodesRemoved(const Array<UInt> & nodes_list, - const Array<UInt> & new_numbering, - const RemovedNodesEvent & event); + void onNodesRemoved(const Array<UInt> & nodes_list, + const Array<UInt> & new_numbering, + const RemovedNodesEvent & event) override; /// function to implement to react on akantu::NewElementsEvent - virtual void onElementsAdded(const Array<Element> & elements_list, - const NewElementsEvent & event); + void onElementsAdded(const Array<Element> & elements_list, + const NewElementsEvent & event) override; /// function to implement to react on akantu::RemovedElementsEvent - virtual void - onElementsRemoved(const Array<Element> & elements_list, - const ElementTypeMapArray<UInt> & new_numbering, - const RemovedElementsEvent & event); + void onElementsRemoved(const Array<Element> & elements_list, + const ElementTypeMapArray<UInt> & new_numbering, + const RemovedElementsEvent & event) override; /// 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); + 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; /// Total number of degrees of freedom (size with the ghosts) UInt local_system_size; /// Number of purely local dofs (size without the ghosts) UInt pure_local_system_size; /// Total number of degrees of freedom UInt system_size; /// Communicator used for this manager, should be the same as in the mesh if a /// mesh is registered const Communicator & communicator; }; } // 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 6944e7da6..8c7d95689 100644 --- a/src/model/dof_manager_default.cc +++ b/src/model/dof_manager_default.cc @@ -1,913 +1,912 @@ /** * @file dof_manager_default.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Tue Aug 11 16:21:01 2015 * * @brief Implementation of the default DOFManager * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager_default.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 "communicator.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")), jacobian_release(0), global_equation_number(0, 1, "global_equation_number"), first_global_dof_id(0), 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, communicator); } /* -------------------------------------------------------------------------- */ 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: typedef typename std::unordered_map<UInt, std::vector<UInt>>::size_type 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 { return dofs_per_node.find(node)->second[nth_dof]; } - virtual UInt getNbData(const Array<UInt> & nodes, - const SynchronizationTag & tag) const { + 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; } - virtual void packData(CommunicationBuffer & buffer, const Array<UInt> & nodes, - const SynchronizationTag & tag) const { + 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; } } } - virtual void unpackData(CommunicationBuffer & buffer, - const Array<UInt> & nodes, - const SynchronizationTag & tag) { + 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() { DOFStorage::iterator it = this->dofs.begin(); DOFStorage::iterator 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); Array<Real>::const_scalar_iterator A_it = A.begin(); Array<Real>::const_scalar_iterator A_end = A.end(); Array<Real>::const_scalar_iterator x_it = data_cache.begin(); Array<Real>::scalar_iterator 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; if (ghost_type == _not_ghost) { nb_element = this->mesh->getNbElement(type); } else { AKANTU_DEBUG_TO_IMPLEMENT(); } 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 (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, 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; } } } } // namespace akantu // LocalWords: dof dofs diff --git a/src/model/dof_manager_default.hh b/src/model/dof_manager_default.hh index 2cb8a89b8..6a70ac77f 100644 --- a/src/model/dof_manager_default.hh +++ b/src/model/dof_manager_default.hh @@ -1,360 +1,360 @@ /** * @file dof_manager_default.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Tue Aug 11 14:06:18 2015 * * @brief Default implementation of the dof manager * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dof_manager.hh" /* -------------------------------------------------------------------------- */ #include <unordered_map> #include <functional> /* -------------------------------------------------------------------------- */ #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); - virtual ~DOFManagerDefault(); + ~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, 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; /// 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; /// 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_inline_impl.cc b/src/model/dof_manager_inline_impl.cc index 0a035af4a..d9dab0b49 100644 --- a/src/model/dof_manager_inline_impl.cc +++ b/src/model/dof_manager_inline_impl.cc @@ -1,154 +1,154 @@ /** * @file dof_manager_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Aug 12 11:07:01 2015 * * @brief * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 { DOFStorage::const_iterator it = this->dofs.find(dof_id); return it != this->dofs.end(); } /* -------------------------------------------------------------------------- */ inline DOFManager::DOFData & DOFManager::getDOFData(const ID & dof_id) { DOFStorage::iterator 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 { DOFStorage::const_iterator 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 != NULL); + 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 != NULL); + 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] == NULL)) + 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] != NULL)); + 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/integration_scheme/integration_scheme.hh b/src/model/integration_scheme/integration_scheme.hh index a13051f22..024313073 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 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "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); - virtual ~IntegrationScheme() = default; + ~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_2nd_order.hh b/src/model/integration_scheme/integration_scheme_2nd_order.hh index 220fbe50b..d60ee5777 100644 --- a/src/model/integration_scheme/integration_scheme_2nd_order.hh +++ b/src/model/integration_scheme/integration_scheme_2nd_order.hh @@ -1,108 +1,108 @@ /** * @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 * * @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) * * Akantu is free 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 "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){}; - virtual ~IntegrationScheme2ndOrder() = default; + ~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.hh b/src/model/integration_scheme/newmark-beta.hh index 795e24125..7373c56a9 100644 --- a/src/model/integration_scheme/newmark-beta.hh +++ b/src/model/integration_scheme/newmark-beta.hh @@ -1,196 +1,196 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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() { return {"M", "C"}; } + 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/model.cc b/src/model/model.cc index 1a17d7ed9..a9ffb9eb7 100644 --- a/src/model/model.cc +++ b/src/model/model.cc @@ -1,350 +1,350 @@ /** * @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 * * @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) * * Akantu is free 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 "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, UInt dim, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), ModelSolver(mesh, 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::initFull(const ModelOptions & options) { AKANTU_DEBUG_IN(); method = options.analysis_method; if (!this->hasDefaultSolver()) { this->initNewSolver(this->method); } initModel(); 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 (!this->hasSolver(solver_name)) { ModelSolverOptions options = this->getDefaultSolverOptions(tss_type); this->getNewSolver(solver_name, tss_type, options.non_linear_solver_type); this->setIntegrationScheme(solver_name, "displacement", options.integration_scheme_type["displacement"], options.solution_type["displacement"]); } this->method = method; this->setDefaultSolver(solver_name); } /* -------------------------------------------------------------------------- */ void Model::initPBC() { std::map<UInt, UInt>::iterator it = pbc_pair.begin(); std::map<UInt, UInt>::iterator end = pbc_pair.end(); is_pbc_slave_node.resize(mesh.getNbNodes()); #ifndef AKANTU_NDEBUG Array<Real>::const_vector_iterator 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::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() { GroupManager::element_group_iterator bit = mesh.element_group_begin(); GroupManager::element_group_iterator bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->dump(); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory) { GroupManager::element_group_iterator bit = mesh.element_group_begin(); GroupManager::element_group_iterator 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, 3); } /* -------------------------------------------------------------------------- */ 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 = NULL; + 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); if (!field) AKANTU_DEBUG_WARNING("No field could be found based on name: " << field_id); 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 8036a5bef..35a359e98 100644 --- a/src/model/model.hh +++ b/src/model/model.hh @@ -1,349 +1,349 @@ /** * @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 * * @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) * * Akantu is free 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 "aka_common.hh" #include "aka_memory.hh" #include "fe_engine.hh" #include "mesh.hh" #include "model_solver.hh" #include "aka_named_argument.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MODEL_HH__ #define __AKANTU_MODEL_HH__ namespace akantu { class SynchronizerRegistry; class Parser; } // namespace akantu /* -------------------------------------------------------------------------- */ 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; }; class DumperIOHelper; class Model : public Memory, public ModelSolver, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Model(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "model", const MemoryID & memory_id = 0); - virtual ~Model(); + ~Model() override; typedef std::map<std::string, std::unique_ptr<FEEngine>> FEEngineMap; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: virtual void initFull(const ModelOptions & options); template <typename P, typename T, typename... pack> void initFull(named_argument::param_t<P, T &&> && first, pack &&... _pack) { this->initFull(ModelOptions{use_named_args, first, _pack...}); } /// 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; // /// 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 - virtual void printself(std::ostream &, int = 0) const {}; + 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_DEBUG_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 NULL; + 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 NULL; + 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 NULL; + 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 NULL; + 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 9d5568242..ef491704e 100644 --- a/src/model/model_inline_impl.cc +++ b/src/model/model_inline_impl.cc @@ -1,215 +1,215 @@ /** * @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 * * @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) * * Akantu is free 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 "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; FEEngineMap::const_iterator 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) { FEEngineMap::iterator 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 FEEngineMap::iterator 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; FEEngineMap::const_iterator 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 != NULL, "The FEEngine boundary " - << tmp_name - << " was not created"); + 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_solver.cc b/src/model/model_solver.cc index 678ae42cb..1225ea251 100644 --- a/src/model/model_solver.cc +++ b/src/model/model_solver.cc @@ -1,359 +1,359 @@ /** * @file model_solver.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Aug 12 13:31:56 2015 * * @brief Implementation of ModelSolver * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 { /* -------------------------------------------------------------------------- */ ModelSolver::ModelSolver(Mesh & mesh, const ID & id, UInt memory_id) : Parsable(_st_model_solver, id), SolverCallback(), parent_id(id), - parent_memory_id(memory_id), mesh(mesh), dof_manager(NULL), + parent_memory_id(memory_id), mesh(mesh), dof_manager(nullptr), default_solver_id("") {} /* -------------------------------------------------------------------------- */ ModelSolver::~ModelSolver() { delete this->dof_manager; } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager() { std::pair<Parser::const_section_iterator, Parser::const_section_iterator> sub_sect = getStaticParser().getSubSections(_st_model_solver); // default without external solver activated at compilation same as mumps that // is the historical solver but with only the lumped solver ID solver_type = "explicit"; #if defined(AKANTU_USE_MUMPS) solver_type = "mumps"; #elif defined(AKANTU_USE_PETSC) solver_type = "petsc"; #endif - const ParserSection * section = NULL; + const ParserSection * section = nullptr; Parser::const_section_iterator it; - for (it = sub_sect.first; it != sub_sect.second && section == NULL; ++it) { + for (it = sub_sect.first; it != sub_sect.second && section == nullptr; ++it) { if (it->getName() == this->parent_id) { section = &(*it); solver_type = section->getOption(solver_type); } } if (section) { this->initDOFManager(*section, solver_type); } else { this->initDOFManager(solver_type); } } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager(const ID & solver_type) { if (solver_type == "explicit") { ID id = this->parent_id + ":dof_manager_default"; this->dof_manager = new DOFManagerDefault(mesh, id, this->parent_memory_id); } else if (solver_type == "petsc") { #if defined(AKANTU_USE_PETSC) ID id = this->parent_id + ":dof_manager_petsc"; this->dof_manager = new DOFManagerPETSc(mesh, id, this->parent_memory_id); #else AKANTU_EXCEPTION( "To use PETSc you have to activate it in the compilations options"); #endif } else if (solver_type == "mumps") { #if defined(AKANTU_USE_MUMPS) ID id = this->parent_id + ":dof_manager_default"; this->dof_manager = new DOFManagerDefault(mesh, id, this->parent_memory_id); #else AKANTU_EXCEPTION( "To use MUMPS you have to activate it in the compilations options"); #endif } else { 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); } /* -------------------------------------------------------------------------- */ template <typename T> static T getOptionToType(const std::string & opt_str) { std::stringstream sstr(opt_str); T opt; sstr >> opt; return opt; } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager(const ParserSection & section, const ID & solver_type) { this->initDOFManager(solver_type); std::pair<Parser::const_section_iterator, Parser::const_section_iterator> sub_sect = section.getSubSections(_st_time_step_solver); Parser::const_section_iterator it; for (it = sub_sect.first; it != sub_sect.second; ++it) { ID solver_id = it->getName(); // std::string str = it->getOption(); TimeStepSolverType tss_type = it->getParameter("type", this->getDefaultSolverType()); ModelSolverOptions tss_options = this->getDefaultSolverOptions(tss_type); std::pair<Parser::const_section_iterator, Parser::const_section_iterator> sub_solvers_sect = it->getSubSections(_st_non_linear_solver); Parser::const_section_iterator sub_it; UInt nb_non_linear_solver_section = it->getNbSubSections(_st_non_linear_solver); NonLinearSolverType nls_type = tss_options.non_linear_solver_type; if (nb_non_linear_solver_section == 1) { const ParserSection & 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 ParserSection & nls_section = *(sub_solvers_sect.first); this->dof_manager->getNonLinearSolver(solver_id).parseSection( nls_section); } std::pair<Parser::const_section_iterator, Parser::const_section_iterator> sub_integrator_sect = it->getSubSections(_st_integration_scheme); for (sub_it = sub_integrator_sect.first; sub_it != sub_integrator_sect.second; ++sub_it) { const ParserSection & is_section = *sub_it; const ID & dof_id = is_section.getName(); IntegrationSchemeType it_type = is_section.getParameter( "type", tss_options.integration_scheme_type[dof_id]); 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); } std::map<ID, IntegrationSchemeType>::const_iterator it = tss_options.integration_scheme_type.begin(); std::map<ID, IntegrationSchemeType>::const_iterator end = tss_options.integration_scheme_type.end(); for (; it != end; ++it) { if (!this->hasIntegrationScheme(solver_id, it->first)) { this->setIntegrationScheme(solver_id, it->first, it->second, tss_options.solution_type[it->first]); } } } if (section.hasParameter("default_solver")) { ID default_solver = section.getParameter("default_solver"); this->setDefaultSolver(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; 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 e6f0aef79..fe6ae060b 100644 --- a/src/model/model_solver.hh +++ b/src/model/model_solver.hh @@ -1,185 +1,185 @@ /** * @file model_solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Jul 22 10:53:10 2015 * * @brief Class regrouping the common solve interface to the different models * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 ID & id, UInt memory_id); - virtual ~ModelSolver(); + ~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(__attribute__((unused)) TimeStepSolverType time_step_solver_type, __attribute__((unused)) NonLinearSolverType non_linear_solver_type) { } /* ------------------------------------------------------------------------ */ /* 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 */ /* ------------------------------------------------------------------------ */ private: ID parent_id; UInt parent_memory_id; /// Underlying mesh Mesh & mesh; /// Underlying dof_manager (the brain...) 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.hh b/src/model/non_linear_solver.hh index 750e0536d..f476b5f02 100644 --- a/src/model/non_linear_solver.hh +++ b/src/model/non_linear_solver.hh @@ -1,96 +1,96 @@ /** * @file non_linear_solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Mon Aug 24 23:48:41 2015 * * @brief Non linear solver interface * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 : 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); - virtual ~NonLinearSolver(); + ~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(); /* ------------------------------------------------------------------------ */ /* 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_linear.hh b/src/model/non_linear_solver_linear.hh index c52b5a693..289fff390 100644 --- a/src/model/non_linear_solver_linear.hh +++ b/src/model/non_linear_solver_linear.hh @@ -1,78 +1,78 @@ /** * @file non_linear_solver_linear.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Tue Aug 25 00:48:07 2015 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "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); - virtual ~NonLinearSolverLinear(); + ~NonLinearSolverLinear() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Function that solve the non linear system described by the dof manager and /// the solver callback functions - virtual void solve(SolverCallback & solver_callback); + 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.hh b/src/model/non_linear_solver_lumped.hh index 834791c3c..9916dcb93 100644 --- a/src/model/non_linear_solver_lumped.hh +++ b/src/model/non_linear_solver_lumped.hh @@ -1,82 +1,82 @@ /** * @file non_linear_solver_lumped.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Tue Aug 25 00:48:07 2015 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "non_linear_solver.hh" #include "sparse_solver_mumps.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); - virtual ~NonLinearSolverLumped(); + ~NonLinearSolverLumped() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Function that solve the non linear system described by the dof manager and /// the solver callback functions - virtual void solve(SolverCallback & solver_callback); + 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.hh b/src/model/non_linear_solver_newton_raphson.hh index 1b07a299d..e1e6539de 100644 --- a/src/model/non_linear_solver_newton_raphson.hh +++ b/src/model/non_linear_solver_newton_raphson.hh @@ -1,104 +1,104 @@ /** * @file non_linear_solver_newton_raphson.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Tue Aug 25 00:48:07 2015 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "non_linear_solver.hh" #include "sparse_solver_mumps.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LINEAR_SOLVER_NEWTON_RAPHSON_HH__ #define __AKANTU_NON_LINEAR_SOLVER_NEWTON_RAPHSON_HH__ namespace akantu { class DOFManagerDefault; } 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); - virtual ~NonLinearSolverNewtonRaphson(); + ~NonLinearSolverNewtonRaphson() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Function that solve the non linear system described by the dof manager and /// the solver callback functions - virtual void solve(SolverCallback & solver_callback); + 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 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; /// Convergence error at last solve call Real error; /// Did the last call to solve reached convergence bool converged; /// Force a re-computation of the jacobian matrix bool force_linear_recompute; }; } // 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 66fff0841..dd99cdfa8 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1606 +1,1606 @@ /** * @file material.cc * * @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 * * @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) * * Akantu is free 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 "material.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Memory(id, model.getMemoryID()), Parsable(_st_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(_st_material, id), is_init(false), fem(model.getFEEngine()), 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("poila_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 (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (std::map<ID, InternalField<bool> *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); is_init = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (std::map<ID, InternalField<Real> *>::iterator 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) { Array<Real> & internal_force = const_cast<Array<Real> &>(model.getInternalForce()); Mesh & mesh = fem.getMesh(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element) { const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(*it, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = fem.getNbIntegrationPoints(*it, ghost_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"); Array<Real> * shapesd_filtered = new Array<Real>(0, size_of_shapes_derivatives, "filtered shapesd"); FEEngine::filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, *it, ghost_type, elem_filter); Array<Real> & stress_vect = this->stress(*it, ghost_type); Array<Real>::matrix_iterator sigma = stress_vect.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator B = shapesd_filtered->begin(spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator Bt_sigma_it = sigma_dphi_dx->begin(spatial_dimension, nb_nodes_per_element); for (UInt q = 0; q < nb_element * nb_quadrature_points; ++q, ++sigma, ++B, ++Bt_sigma_it) Bt_sigma_it->mul<false, false>(*sigma, *B); delete shapesd_filtered; /** * 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, *it, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble model.getDOFManager().assembleElementalArrayLocalArray( *int_sigma_dphi_dx, internal_force, *it, 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()) { 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); Array<Real> * shapesd_filtered = new Array<Real>( nb_element, dim * nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapesd_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> Bt_D(dim * nb_nodes_per_element, tangent_size); Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator Bt_D_B_it = bt_d_b->begin(dim * nb_nodes_per_element, dim * nb_nodes_per_element); Array<Real>::matrix_iterator D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); Array<Real>::matrix_iterator 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) { Matrix<Real> & D = *D_it; Matrix<Real> & Bt_D_B = *Bt_D_B_it; VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_D.mul<true, false>(B, D); Bt_D_B.mul<false, false>(Bt_D, B); } delete tangent_stiffness_matrix; delete shapesd_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::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); // gradu_vect.resize(nb_quadrature_points * nb_element); // fem.gradientOnIntegrationPoints(model.getIncrement(), gradu_vect, // dim, type, ghost_type, &elem_filter); Array<Real> * shapes_derivatives_filtered = new Array<Real>( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); Array<Real>::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// 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); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size); Array<Real>::matrix_iterator Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size); Array<Real>::matrix_iterator 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) { Matrix<Real> & Bt_S_B = *Bt_S_B_it; Matrix<Real> & 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.mul<true, false>(B, S); Bt_S_B.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"); Array<Real>::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// 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); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator Bt_D_B_it = bt_d_b->begin(dim * nb_nodes_per_element, dim * nb_nodes_per_element); Array<Real>::matrix_iterator grad_u_it = gradu_vect.begin(dim, dim); Array<Real>::matrix_iterator D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); Array<Real>::matrix_iterator 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) { Matrix<Real> & grad_u = *grad_u_it; Matrix<Real> & D = *D_it; Matrix<Real> & 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.mul<true, false>(B, D); Bt_D_B.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"); FEEngine::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; Array<Real> * bt_s = new Array<Real>(nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); Array<Real>::matrix_iterator grad_u_it = this->gradu(type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator grad_u_end = this->gradu(type, ghost_type).end(dim, dim); Array<Real>::matrix_iterator 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) { Matrix<Real> & grad_u = *grad_u_it; Matrix<Real> & r_it = *bt_s_it; Matrix<Real> & 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.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::computeAllStressesFromTangentModuli(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { switch (spatial_dimension) { case 1: { computeAllStressesFromTangentModuli<1>(type, ghost_type); break; } case 2: { computeAllStressesFromTangentModuli<2>(type, ghost_type); break; } case 3: { computeAllStressesFromTangentModuli<3>(type, ghost_type); break; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::computeAllStressesFromTangentModuli(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(); if (nb_element) { 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); Array<Real> & disp = model.getDisplacement(); fem.gradientOnIntegrationPoints(disp, gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_moduli_size = getTangentStiffnessVoigtSize(dim); Array<Real> * tangent_moduli_tensors = new Array<Real>( nb_element * nb_quadrature_points, tangent_moduli_size * tangent_moduli_size, "tangent_moduli_tensors"); tangent_moduli_tensors->clear(); computeTangentModuli(type, *tangent_moduli_tensors, ghost_type); Array<Real> * shapesd_filtered = new Array<Real>( nb_element, dim * nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); Array<Real> filtered_u(nb_element, nb_nodes_per_element * spatial_dimension); FEEngine::extractNodalToElementField(fem.getMesh(), disp, filtered_u, type, ghost_type, elem_filter); /// compute @f$\mathbf{D} \mathbf{B} \mathbf{u}@f$ Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator D_it = tangent_moduli_tensors->begin(tangent_moduli_size, tangent_moduli_size); Array<Real>::matrix_iterator sigma_it = stress(type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::vector_iterator u_it = filtered_u.begin(spatial_dimension * nb_nodes_per_element); Matrix<Real> B(tangent_moduli_size, spatial_dimension * nb_nodes_per_element); Vector<Real> Bu(tangent_moduli_size); Vector<Real> DBu(tangent_moduli_size); for (UInt e = 0; e < nb_element; ++e, ++u_it) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it, ++shapes_derivatives_filtered_it, ++sigma_it) { Vector<Real> & u = *u_it; Matrix<Real> & sigma = *sigma_it; Matrix<Real> & D = *D_it; VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bu.mul<false>(B, u); DBu.mul<false>(D, Bu); // Voigt notation to full symmetric tensor for (UInt i = 0; i < dim; ++i) sigma(i, i) = DBu(i); if (dim == 2) { sigma(0, 1) = sigma(1, 0) = DBu(2); } else if (dim == 3) { sigma(1, 2) = sigma(2, 1) = DBu(3); sigma(0, 2) = sigma(2, 0) = DBu(4); sigma(0, 1) = sigma(1, 0) = DBu(5); } } } } 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(std::string type) { AKANTU_DEBUG_IN(); if (type == "potential") return getPotentialEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(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 = NULL; + const Array<std::vector<Element>> * element_to_facet = nullptr; GhostType current_ghost_type = _casper; - Array<Real> * result_vec = NULL; + 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(__attribute__((unused)) const ID & vect_id, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <typename T> Array<T> & Material::getArray(__attribute__((unused)) const ID & vect_id, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ 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_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T> & Material::getInternal(__attribute__((unused)) const ID & int_id) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <> const InternalField<Real> & Material::getInternal(const ID & int_id) const { std::map<ID, InternalField<Real> *>::const_iterator 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) { std::map<ID, InternalField<Real> *>::iterator 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 { std::map<ID, InternalField<UInt> *>::const_iterator 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) { std::map<ID, InternalField<UInt> *>::iterator 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 (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map<ID, InternalField<bool> *>::iterator 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 (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (std::map<ID, InternalField<bool> *>::iterator 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()); Array<Element>::const_iterator<Element> el_begin = element_list.begin(); Array<Element>::const_iterator<Element> el_end = element_list.end(); for (ghost_type_t::iterator g = ghost_type_t::begin(); g != ghost_type_t::end(); ++g) { GhostType gt = *g; ElementTypeMapArray<UInt>::type_iterator it = new_numbering.firstType(_all_dimensions, gt, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = new_numbering.lastType(_all_dimensions, gt, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; if (element_filter.exists(type, gt) && element_filter(type, gt).size()) { Array<UInt> & elem_filter = element_filter(type, gt); Array<UInt> & mat_indexes = this->model.getMaterialByElement(*it, gt); Array<UInt> & mat_loc_num = this->model.getMaterialLocalNumbering(*it, gt); UInt 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); Array<UInt> & mat_renumbering = material_local_new_numbering(type, gt); const Array<UInt> & 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 (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map<ID, InternalField<bool> *>::iterator 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 311e68a66..db578d06c 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,683 +1,681 @@ /** * @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 * * @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) * * Akantu is free 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 "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 - virtual ~Material(); + ~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_DEBUG_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_DEBUG_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_DEBUG_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_DEBUG_TO_IMPLEMENT(); } /// compute the s-wave speed in the material virtual Real getShearWaveSpeed(__attribute__((unused)) const Element & element) const { AKANTU_DEBUG_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_DEBUG_TO_IMPLEMENT(); } template <typename T> void unregisterInternal(__attribute__((unused)) InternalField<T> & vect) { AKANTU_DEBUG_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 - virtual void printself(std::ostream & stream, int indent = 0) const; + 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: - virtual inline UInt getNbData(const Array<Element> & elements, - const SynchronizationTag & tag) const; + inline UInt getNbData(const Array<Element> & elements, + const SynchronizationTag & tag) const override; - virtual inline void packData(CommunicationBuffer & buffer, - const Array<Element> & elements, - const SynchronizationTag & tag) const; + inline void packData(CommunicationBuffer & buffer, + const Array<Element> & elements, + const SynchronizationTag & tag) const override; - virtual inline void unpackData(CommunicationBuffer & buffer, - const Array<Element> & elements, - const SynchronizationTag & tag); + 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: /* ------------------------------------------------------------------------ */ - virtual void onNodesAdded(const Array<UInt> &, const NewNodesEvent &){}; - virtual void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, - const RemovedNodesEvent &){}; + void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) override{}; + void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, + const RemovedNodesEvent &) override{}; - virtual void onElementsAdded(const Array<Element> & element_list, - const NewElementsEvent & event); + void onElementsAdded(const Array<Element> & element_list, + const NewElementsEvent & event) override; - virtual void - onElementsRemoved(const Array<Element> & element_list, - const ElementTypeMapArray<UInt> & new_numbering, - const RemovedElementsEvent & event); + void onElementsRemoved(const Array<Element> & element_list, + const ElementTypeMapArray<UInt> & new_numbering, + const RemovedElementsEvent & event) override; - virtual void onElementsChanged(const Array<Element> &, const Array<Element> &, - const ElementTypeMapArray<UInt> &, - const ChangedElementsEvent &){}; + void onElementsChanged(const Array<Element> &, const Array<Element> &, + const ElementTypeMapArray<UInt> &, + const ChangedElementsEvent &) override{}; /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void beforeSolveStep(); virtual void afterSolveStep(); - - virtual void onDamageIteration(); - virtual void onDamageUpdate(); - virtual void onDump(); + 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(std::string energy_id); /// return the energy (identified by id) for the provided element virtual Real getEnergy(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, 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 = \ MaterialFactory::getInstance().registerAllocator( \ #id, MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name)) #endif /* __AKANTU_MATERIAL_HH__ */ diff --git a/src/model/solid_mechanics/material_selector.hh b/src/model/solid_mechanics/material_selector.hh index d49b9e4f8..6759d1967 100644 --- a/src/model/solid_mechanics/material_selector.hh +++ b/src/model/solid_mechanics/material_selector.hh @@ -1,142 +1,142 @@ /** * @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 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "aka_common.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #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: MaterialSelector() : fallback_value(0) {} virtual ~MaterialSelector() {} virtual UInt operator()(__attribute__((unused)) const Element & element) { return fallback_value; } void setFallback(UInt f) { fallback_value = f; } protected: UInt fallback_value; }; /* -------------------------------------------------------------------------- */ /** * 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) { + UInt operator()(const Element & element) override { if (not material_index.exists(element.type, element.ghost_type)) return fallback_value; 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 fallback_value; } 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) { + 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/materials/internal_field.hh b/src/model/solid_mechanics/materials/internal_field.hh index 25cd18f86..96df05f34 100644 --- a/src/model/solid_mechanics/materials/internal_field.hh +++ b/src/model/solid_mechanics/materials/internal_field.hh @@ -1,257 +1,257 @@ /** * @file internal_field.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Dec 08 2015 * * @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) * * Akantu is free 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 "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); - virtual ~InternalField(); + ~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 - virtual void printself(std::ostream & stream, int indent = 0) const; + 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: typedef typename ElementTypeMapArray<T>::type_iterator type_iterator; typedef typename ElementTypeMapArray<UInt>::type_iterator filter_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 != NULL, + 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 != NULL, + 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 != NULL, + 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 != NULL, + 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 != NULL); } + 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 88d2b2539..85147ea95 100644 --- a/src/model/solid_mechanics/materials/internal_field_tmpl.hh +++ b/src/model/solid_mechanics/materials/internal_field_tmpl.hh @@ -1,320 +1,320 @@ /** * @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 * * @brief Material internal properties * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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(NULL) {} + 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(NULL) {} + 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(NULL) {} + 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(NULL) { + 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 = NULL; + 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 != NULL, + 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 (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { ElementTypeMapArray<UInt>::type_iterator it = new_numbering.firstType(_all_dimensions, *gt, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = new_numbering.lastType(_all_dimensions, *gt, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; if (this->exists(type, *gt)) { Array<T> & vect = this->operator()(type, *gt); if (!vect.size()) continue; const Array<UInt> & renumbering = new_numbering(type, *gt); UInt nb_quad_per_elem = fem->getNbIntegrationPoints(type, *gt); 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) 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_elastic.hh b/src/model/solid_mechanics/materials/material_elastic.hh index f28f92293..791043bf6 100644 --- a/src/model/solid_mechanics/materials/material_elastic.hh +++ b/src/model/solid_mechanics/materials/material_elastic.hh @@ -1,158 +1,158 @@ /** * @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 * * @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) * * Akantu is free 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 "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: typedef PlaneStressToolbox<spatial_dimension, MaterialThermal<spatial_dimension>> Parent; public: MaterialElastic(SolidMechanicsModel & model, const ID & id = ""); MaterialElastic(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); - virtual ~MaterialElastic() {} + ~MaterialElastic() override {} protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - virtual void initMaterial(); + 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; - virtual void + void computePotentialEnergyByElement(ElementType type, UInt index, - Vector<Real> & epot_on_quad_points); + 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 - virtual Real getShearWaveSpeed(const Element & element) const; + 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 - virtual void updateInternalParameters(); + void updateInternalParameters() override; static inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot); - virtual bool hasStiffnessMatrixChanged() { + 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_thermal.hh b/src/model/solid_mechanics/materials/material_thermal.hh index 792d6097a..c9aad9194 100644 --- a/src/model/solid_mechanics/materials/material_thermal.hh +++ b/src/model/solid_mechanics/materials/material_thermal.hh @@ -1,106 +1,106 @@ /** * @file material_thermal.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Aug 18 2015 * * @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) * * Akantu is free 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 "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 = ""); - virtual ~MaterialThermal() {}; + ~MaterialThermal() override{}; protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - virtual void initMaterial(); + void initMaterial() override; /// constitutive law for all element of a type - virtual void computeStress(ElementType el_type, GhostType ghost_type); + void computeStress(ElementType el_type, GhostType ghost_type) override; /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* 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; }; } // akantu #endif /* __AKANTU_MATERIAL_THERMAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/plane_stress_toolbox.hh b/src/model/solid_mechanics/materials/plane_stress_toolbox.hh index 4a5e0c45b..3eb0ee11b 100644 --- a/src/model/solid_mechanics/materials/plane_stress_toolbox.hh +++ b/src/model/solid_mechanics/materials/plane_stress_toolbox.hh @@ -1,106 +1,106 @@ /** * @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 * * @brief Tools to implement the plane stress behavior in a material * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #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) {} - virtual ~PlaneStressToolbox() {} + ~PlaneStressToolbox() override {} protected: void initialize(); public: - virtual void computeAllCauchyStresses(GhostType ghost_type = _not_ghost) { + void computeAllCauchyStresses(GhostType ghost_type = _not_ghost) override { AKANTU_DEBUG_IN(); ParentMaterial::computeAllCauchyStresses(ghost_type); AKANTU_DEBUG_OUT(); } virtual void computeCauchyStressPlaneStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ERROR("The function \"computeCauchyStressPlaneStress\" can " "only be used in 2D Plane stress problems, which means " "that you made a mistake somewhere!! "); AKANTU_DEBUG_OUT(); } protected: bool initialize_third_axis_deformation; }; #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 ecf88c1f4..e31099310 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 * * @brief 2D specialization of the akantu::PlaneStressToolbox class * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 = ""); - virtual ~PlaneStressToolbox() {} + ~PlaneStressToolbox() override {} 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: /* ------------------------------------------------------------------------ */ - virtual void initMaterial() { + 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(); } } /* ------------------------------------------------------------------------ */ - virtual void computeStress(ElementType el_type, GhostType ghost_type) { + 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 - virtual void computeAllCauchyStresses(GhostType ghost_type = _not_ghost) { + 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 66ee3d1a9..f3e6decda 100644 --- a/src/model/solid_mechanics/materials/random_internal_field.hh +++ b/src/model/solid_mechanics/materials/random_internal_field.hh @@ -1,108 +1,108 @@ /** * @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 * * @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) * * Akantu is free 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 "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); - virtual ~RandomInternalField(); + ~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 - virtual void initialize(UInt nb_component); + void initialize(UInt nb_component) override; /// set the field to a given value - void setDefaultValue(const T & 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 - virtual void printself(std::ostream & stream, int indent = 0) const; + void printself(std::ostream & stream, int indent = 0) const override; protected: - virtual void setArrayValues(T * begin, T * end); + 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/weight_functions/damaged_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/damaged_weight_function.hh index 2ef20c741..7ffbfdbf3 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 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 * * @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) * * Akantu is free 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 "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(NULL) { + : BaseWeightFunction(manager, "damaged"), damage(nullptr) { this->init(); } /* -------------------------------------------------------------------------- */ /* Base Weight Function inherited methods */ /* -------------------------------------------------------------------------- */ /// set the pointers of internals to the right flattend version - virtual void init(); + 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/remove_damaged_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function.hh index 54b9c49b7..3a5ca0524 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 * * @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) * * Akantu is free 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 "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(NULL) { + : 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 */ /* -------------------------------------------------------------------------- */ - virtual inline void init(); + 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_with_damage_rate_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function.hh index dca670cba..31eb2dbc8 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,82 +1,83 @@ /** * @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 * * @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) * * Akantu is free 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 "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(NULL) { + 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); - virtual inline void init(); + 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/stress_based_weight_function.hh b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.hh index fd3e0744e..07a742faa 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,104 +1,104 @@ /** * @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 * * @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) * * Akantu is free 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 "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(); + void init() override; - virtual inline void updateInternals(); + 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/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index c0f013d23..495e28103 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,581 +1,581 @@ /** * @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 * * @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) * * Akantu is free 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 "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" /* -------------------------------------------------------------------------- */ //#include "integrator_gauss.hh" //#include "shape_lagrange.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 { struct SolidMechanicsModelOptions : public ModelOptions { explicit SolidMechanicsModelOptions( AnalysisMethod analysis_method = _explicit_lumped_mass); template <typename... pack> SolidMechanicsModelOptions(use_named_args_t, pack &&... _pack); }; /* -------------------------------------------------------------------------- */ 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); - virtual ~SolidMechanicsModel(); + ~SolidMechanicsModel() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template <typename P, typename T, typename... pack> void initFull(named_argument::param_t<P, T &&> && first, pack &&... _pack) { this->initFull(SolidMechanicsModelOptions{use_named_args, first, _pack...}); } /// initialize completely the model void initFull( const ModelOptions & options = SolidMechanicsModelOptions()) override; /// initialize the fem object needed for boundary conditions void initFEEngineBoundary(); protected: /// 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; /// 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 void - assignMaterialToElements(const ElementTypeMapArray<UInt> * filter = NULL); + 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(); } inline void setMaterialSelector(MaterialSelector & selector); /// 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); /// get the FEEngine object to integrate or interpolate on the boundary FEEngine & getFEEngineBoundary(const ID & name = "") override; 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); /// Access the non_local_manager interface AKANTU_GET_MACRO(NonLocalManager, *non_local_manager, NonLocalManager &); 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; #ifdef SWIGPYTHON public: #endif /// 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; #ifdef SWIGPYTHON protected: #endif /// class defining of to choose a material MaterialSelector * material_selector; /// define if it is the default selector or not bool is_default_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; typedef std::map<std::pair<std::string, ElementKind>, ElementTypeMapArray<Real> *> flatten_internal_map; /// 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 { typedef FromHigherDim FromStress; typedef FromSameDim FromTraction; } // 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 80bd758d2..1d001ff32 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,615 +1,615 @@ /** * @file fragment_manager.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Thu Jan 23 2014 * @date last modification: Mon Dec 14 2015 * * @brief Group manager to handle fragments * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fragment_manager.hh" #include "aka_iterators.hh" #include "material_cohesive.hh" #include "mesh_iterators.hh" #include "solid_mechanics_model_cohesive.hh" #include "communicator.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 { + 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 MaterialCohesive & 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 Array<Real>::const_vector_iterator 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); Array<Real>::const_vector_iterator 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); Array<Real>::vector_iterator 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(); Array<Real>::vector_iterator 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); Array<Real>::const_vector_iterator 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/material_selector_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/material_selector_cohesive.hh index 84b18a443..269fdd115 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,75 +1,76 @@ /** * @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 * * @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) * * Akantu is free 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 "material_selector.hh" /* -------------------------------------------------------------------------- */ 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 DefaultMaterialSelector { public: DefaultMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model); - virtual UInt operator()(const Element & element); + 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 MeshDataMaterialSelector<std::string> { public: MeshDataMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model); - virtual UInt operator()(const Element & element); + UInt operator()(const Element & element) override; + protected: const Mesh &mesh_facets; const ElementTypeMapArray<UInt> & material_index; bool third_dimension; }; #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 241604669..946884013 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,70 +1,71 @@ /** * @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 * * @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) * * Akantu is free 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 "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); - virtual ~CohesiveInternalField(); + ~CohesiveInternalField() override; /// initialize the field to a given number of component - void initialize(UInt nb_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); - virtual ~FacetInternalField(); + ~FacetInternalField() override; /// initialize the field to a given number of component - void initialize(UInt nb_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/material_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh index 52c228a0d..ee1d80f9d 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,261 +1,256 @@ /** * @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 * * @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) * * Akantu is free 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 "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: typedef FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive> MyFEEngineCohesiveType; public: MaterialCohesive(SolidMechanicsModel & model, const ID & id = ""); - virtual ~MaterialCohesive(); + ~MaterialCohesive() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter - virtual void initMaterial(); + 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); + void assembleInternalForces(GhostType ghost_type = _not_ghost) override; /// compute reversible and total energies by element void computeEnergies(); /// check stress for cohesive elements' insertion, by default it /// also updates the cohesive elements' data - virtual void checkInsertion(__attribute__((unused)) bool check_only = false) { + virtual void checkInsertion(bool /*check_only*/ = false) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// check delta_max for cohesive elements in case of no convergence /// in the solveStep (only for extrinsic-implicit) - virtual void checkDeltaMax(__attribute__((unused)) - GhostType ghost_type = _not_ghost) { + virtual void checkDeltaMax(GhostType /*ghost_type*/ = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// reset variables when convergence is reached (only for /// extrinsic-implicit) - virtual void resetVariables(__attribute__((unused)) - GhostType ghost_type = _not_ghost) { + virtual void resetVariables(GhostType /*ghost_type*/ = _not_ghost) { AKANTU_DEBUG_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(__attribute__((unused)) const ElementType type, - __attribute__((unused)) - Array<Real> & result){}; + virtual void interpolateStress(const ElementType /*type*/, + + Array<Real> & /*result*/){}; /// compute the stresses - virtual void computeAllStresses(__attribute__((unused)) - GhostType ghost_type = _not_ghost){}; + 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(__attribute__((unused)) const ElementType & el_type, - __attribute__((unused)) Array<Real> & tangent_matrix, - __attribute__((unused)) const Array<Real> & normal, - __attribute__((unused)) - GhostType ghost_type = _not_ghost) { + virtual void computeTangentTraction(const ElementType & /*el_type*/, + Array<Real> & /*tangent_matrix*/, + const Array<Real> & /*normal*/, + GhostType /*ghost_type*/ = _not_ghost) { AKANTU_DEBUG_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); + 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); /* ------------------------------------------------------------------------ */ /* 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 - virtual Real getEnergy(std::string type); + Real getEnergy(std::string type) override; /// return the energy (identified by id) for the provided element - virtual Real getEnergy(std::string energy_id, ElementType type, UInt index) { + Real getEnergy(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; /// opening in all elements and quadrature points (previous time step) CohesiveInternalField<Real> opening_old; /// traction in all elements and quadrature points CohesiveInternalField<Real> tractions; /// traction in all elements and quadrature points (previous time step) CohesiveInternalField<Real> tractions_old; /// 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/solid_mechanics_model_cohesive_parallel.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc index 551bd967e..7dbc2a198 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,397 +1,397 @@ /** * @file solid_mechanics_model_cohesive_parallel.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Functions for parallel cohesive elements * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "solid_mechanics_model_cohesive.hh" #include "solid_mechanics_model_tmpl.hh" #include "communicator.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, _ghost_type = _not_ghost); 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]; auto && cohesive_type = FEEngine::getCohesiveElementType(facet.type); auto old_nb_cohesive_elements = mesh.getNbElement(cohesive_type, facet.ghost_type); old_nb_cohesive_elements -= mesh.getData<UInt>("facet_to_double", facet.type, facet.ghost_type).size(); if (cohesive_element.kind() == _ek_cohesive and 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 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()); }); } /* -------------------------------------------------------------------------- */ 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 = 0; Mesh & mesh_facets = inserter->getMeshFacets(); - Array<T> * vect = NULL; - Array<std::vector<Element>> * element_to_facet = NULL; + 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 != 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; } 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; } default: { SolidMechanicsModel::packData(buffer, elements, tag); } } } else 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; } default: { SolidMechanicsModel::unpackData(buffer, elements, tag); } } } else 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_mass.cc b/src/model/solid_mechanics/solid_mechanics_model_mass.cc index b44d2e995..9cce541a0 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_mass.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_mass.cc @@ -1,159 +1,159 @@ /** * @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 * * @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) * * Akantu is free 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 "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 == NULL) { + 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(); MyFEEngineType & 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(); MyFEEngineType & 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/time_step_solver.hh b/src/model/time_step_solver.hh index c1d44e7d4..fab8342e3 100644 --- a/src/model/time_step_solver.hh +++ b/src/model/time_step_solver.hh @@ -1,132 +1,132 @@ /** * @file time_step_solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Mon Aug 24 12:42:04 2015 * * @brief This corresponding to the time step evolution solver * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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); - virtual ~TimeStepSolver(); + ~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 &) override final { return _mt_not_defined; } + 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) override final; + void assembleLumpedMatrix(const ID & matrix_id) final; /// implementation of the SolverCallback::assembleResidual() void assembleResidual() override; void beforeSolveStep() override; void afterSolveStep() override; /* ------------------------------------------------------------------------ */ /* 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_default.cc b/src/model/time_step_solvers/time_step_solver_default.cc index dcf576d46..747378f1d 100644 --- a/src/model/time_step_solvers/time_step_solver_default.cc +++ b/src/model/time_step_solvers/time_step_solver_default.cc @@ -1,282 +1,282 @@ /** * @file time_step_solver_default.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Sep 16 10:20:55 2015 * * @brief Default implementation of the time step solver * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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_DEBUG_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 = NULL; + 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(); } /* -------------------------------------------------------------------------- */ } // 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 fd7cfc201..e77633ca1 100644 --- a/src/model/time_step_solvers/time_step_solver_default.hh +++ b/src/model/time_step_solvers/time_step_solver_default.hh @@ -1,111 +1,111 @@ /** * @file time_step_solver_default.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Mon Aug 24 17:10:29 2015 * * @brief Default implementation for the time stepper * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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); - virtual ~TimeStepSolverDefault(); + ~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; /// implementation of the generic TimeStepSolver::solveStep() void solveStep(SolverCallback & solver_callback) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: typedef std::map<ID, std::unique_ptr<IntegrationScheme>> DOFsIntegrationSchemes; typedef std::map<ID, IntegrationScheme::SolutionType> DOFsIntegrationSchemesSolutionTypes; typedef std::set<ID> DOFsIntegrationSchemesOwner; /// 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/python/python_functor.hh b/src/python/python_functor.hh index 970419e0a..7516baeea 100644 --- a/src/python/python_functor.hh +++ b/src/python/python_functor.hh @@ -1,127 +1,129 @@ /** * @file python_functor.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Sun Nov 15 2015 * * @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) * * Akantu is free 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 <Python.h> -/* -------------------------------------------------------------------------- */ #include "aka_common.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 */ /* ------------------------------------------------------------------------ */ protected: /// 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 inline void packArguments(std::vector<PyObject *> & pArgs) const; /// 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> inline void packArguments(std::vector<PyObject *> & pArgs, T & p, Args &... params) const; /// convert an akantu object to python template <typename T> inline PyObject * convertToPython(const T & akantu_obj) const; /// convert a stl vector to python template <typename T> inline PyObject * convertToPython(const std::vector<T> & akantu_obj) const; /// convert a stl vector to python template <typename T> inline PyObject * convertToPython(const std::vector<Array<T> *> & akantu_obj) const; /// convert a stl vector to python template <typename T1, typename T2> inline PyObject * convertToPython(const std::map<T1, T2> & akantu_obj) const; /// convert an akantu vector to python template <typename T> inline PyObject * convertToPython(const Vector<T> & akantu_obj) const; /// convert an akantu vector to python template <typename T> inline PyObject * convertToPython(const Array<T> & akantu_obj) const; /// convert an akantu vector to python template <typename T> inline PyObject * convertToPython(Array<T> * akantu_obj) const; /// convert a akantu matrix to python template <typename T> inline PyObject * convertToPython(const Matrix<T> & akantu_obj) const; /// convert a python object to an akantu object template <typename return_type> inline return_type convertToAkantu(PyObject * python_obj) const; /// convert a python object to an akantu object template <typename T> inline std::vector<T> convertListToAkantu(PyObject * python_obj) const; /// returns the numpy data type code template <typename T> inline int getPythonDataTypeCode() const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: PyObject * python_obj; }; -/* -------------------------------------------------------------------------- */ + } // akantu -/* -------------------------------------------------------------------------- */ -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#include "python_functor_inline_impl.cc" #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 a652c938c..ad679181d 100644 --- a/src/python/python_functor_inline_impl.cc +++ b/src/python/python_functor_inline_impl.cc @@ -1,316 +1,319 @@ /** * @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 * * @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) * * Akantu is free 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 "integration_point.hh" /* -------------------------------------------------------------------------- */ #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <numpy/arrayobject.h> #include <typeinfo> /* -------------------------------------------------------------------------- */ +#ifndef __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__ +#define __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__ + namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T> inline int PythonFunctor::getPythonDataTypeCode() const { AKANTU_EXCEPTION("undefined type: " << debug::demangle(typeid(T).name())); } /* -------------------------------------------------------------------------- */ template <> inline int PythonFunctor::getPythonDataTypeCode<bool>() const { 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>() const { return NPY_DOUBLE; } /* -------------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const T &) const { AKANTU_DEBUG_ERROR( __func__ << " : not implemented yet !" << std::endl << debug::demangle(typeid(T).name())); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<double>(const double & akantu_object) const { return PyFloat_FromDouble(akantu_object); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<UInt>(const UInt & akantu_object) const { return PyInt_FromLong(akantu_object); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<bool>(const bool & akantu_object) const { return PyBool_FromLong(long(akantu_object)); } /* -------------------------------------------------------------------------- */ template <typename T> inline PyObject * PythonFunctor::convertToPython(const std::vector<T> & array) const { 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])); PyArrayObject * res = (PyArrayObject *)obj; return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T> inline PyObject * PythonFunctor::convertToPython(const std::vector<Array<T> *> & array) const { PyObject * res = PyDict_New(); for (auto a : array) { PyObject * obj = this->convertToPython(*a); PyObject * name = this->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) const { PyObject * res = PyDict_New(); for (auto a : map) { PyObject * key = this->convertToPython(a.first); PyObject * value = this->convertToPython(a.second); PyDict_SetItem(res, key, value); } return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const Vector<T> & array) const { int data_typecode = getPythonDataTypeCode<T>(); npy_intp dims[1] = {array.size()}; PyObject * obj = PyArray_SimpleNewFromData(1, dims, data_typecode, array.storage()); PyArrayObject * res = (PyArrayObject *)obj; return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const Array<T> & array) const { int data_typecode = getPythonDataTypeCode<T>(); npy_intp dims[2] = {array.size(), array.getNbComponent()}; PyObject * obj = PyArray_SimpleNewFromData(2, dims, data_typecode, array.storage()); PyArrayObject * res = (PyArrayObject *)obj; return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(Array<T> * array) const { return this->convertToPython(*array); } /* -------------------------------------------------------------------------- */ template <typename T> PyObject * PythonFunctor::convertToPython(const Matrix<T> & mat) const { 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()); PyArrayObject * res = (PyArrayObject *)obj; return (PyObject *)res; } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<std::string>(const std::string & str) const { return PyString_FromString(str.c_str()); } /* -------------------------------------------------------------------------- */ template <> inline PyObject * PythonFunctor::convertToPython<IntegrationPoint>( const IntegrationPoint & qp) const { PyObject * input = PyDict_New(); PyObject * num_point = this->convertToPython(qp.num_point); PyObject * global_num = this->convertToPython(qp.global_num); PyObject * material_id = this->convertToPython(qp.material_id); PyObject * position = this->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 (!PyInstance_Check(this->python_obj)) AKANTU_EXCEPTION("Python object is not an instance"); PyObject * pFunctor = PyObject_GetAttrString(this->python_obj, functor_name.c_str()); if (!pFunctor) AKANTU_EXCEPTION("Python dictionary has no " << functor_name << " entry"); return pFunctor; } /* -------------------------------------------------------------------------- */ inline void PythonFunctor::packArguments(__attribute__((unused)) std::vector<PyObject *> & p_args) const {} /* -------------------------------------------------------------------------- */ template <typename T, typename... Args> inline void PythonFunctor::packArguments(std::vector<PyObject *> & p_args, T & p, Args &... params) const { p_args.push_back(this->convertToPython(p)); if (sizeof...(params) != 0) this->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 = 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) const { if (PyList_Check(python_obj)) { return this->convertListToAkantu<typename return_type::value_type>( python_obj); } AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <> inline void PythonFunctor::convertToAkantu<void>(PyObject * python_obj) const { 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) const { if (!PyString_Check(python_obj)) AKANTU_EXCEPTION("cannot convert object to string"); return PyString_AsString(python_obj); } /* -------------------------------------------------------------------------- */ template <> inline Real PythonFunctor::convertToAkantu<Real>(PyObject * python_obj) const { 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) const { if (!PyInt_Check(python_obj)) AKANTU_EXCEPTION("cannot convert object to integer"); return PyInt_AsLong(python_obj); } /* -------------------------------------------------------------------------- */ template <typename T> inline std::vector<T> PythonFunctor::convertListToAkantu(PyObject * python_obj) const { 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(this->convertToAkantu<T>(item)); } return res; } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__ */ diff --git a/src/solver/sparse_matrix_aij.hh b/src/solver/sparse_matrix_aij.hh index 3b015e8aa..11d04b448 100644 --- a/src/solver/sparse_matrix_aij.hh +++ b/src/solver/sparse_matrix_aij.hh @@ -1,179 +1,179 @@ /** * @file sparse_matrix_aij.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Mon Aug 17 21:22:57 2015 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "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"); - virtual ~SparseMatrixAIJ(); + ~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_solver.hh b/src/solver/sparse_solver.hh index dbdbf4f8f..8ac558ef3 100644 --- a/src/solver/sparse_solver.hh +++ b/src/solver/sparse_solver.hh @@ -1,122 +1,122 @@ /** * @file sparse_solver.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 Jan 19 2016 * * @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) * * Akantu is free 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 "aka_memory.hh" //#include "data_accessor.hh" #include "parsable.hh" #include "communicator.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); - virtual ~SparseSolver(); + ~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: - virtual void onCommunicatorFinalize(); + void onCommunicatorFinalize() override; -// inline virtual UInt getNbDataForDOFs(const Array<UInt> & dofs, + // 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 const Communicator & communicator; }; } // akantu #endif /* __AKANTU_SOLVER_HH__ */ diff --git a/src/solver/sparse_solver_mumps.cc b/src/solver/sparse_solver_mumps.cc index 4be72ba7a..5f5313299 100644 --- a/src/solver/sparse_solver_mumps.cc +++ b/src/solver/sparse_solver_mumps.cc @@ -1,440 +1,441 @@ /** * @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 * * @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) * * Akantu is free 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/>. * * @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(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::destroyInternalData() { if (this->is_initialized) { this->mumps_data.job = _smj_destroy; // destroy dmumps_c(&this->mumps_data); this->is_initialized = false; } } /* -------------------------------------------------------------------------- */ 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 = NULL; this->mumps_data.jcn = NULL; } break; default: AKANTU_DEBUG_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 - // [[fallthrough]]; un-comment when compiler will get it + /* FALLTHRU */ + /* [[fallthrough]]; un-comment when compiler will get it */ case _fully_distributed: #ifdef AKANTU_USE_MPI const MPICommunicatorData & 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_DEBUG_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_DEBUG_ERROR("The matrix is singular"); 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_DEBUG_ERROR("The MUMPS workarray is too small INFO(2)=" << info(2) << "No further increase possible"); } break; } default: AKANTU_DEBUG_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 1787f52c3..f200333b5 100644 --- a/src/solver/sparse_solver_mumps.hh +++ b/src/solver/sparse_solver_mumps.hh @@ -1,157 +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 * * @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) * * Akantu is free 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 "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); - virtual ~SparseSolverMumps(); + ~SparseSolverMumps() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// build the profile and do the analysis part - virtual void initialize(); + void initialize() override; /// analysis (symbolic facto + permutations) - virtual void analysis(); + void analysis() override; /// factorize the matrix - virtual void factorize(); + 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 - virtual void solve(); + 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 - virtual void destroyInternalData(); + void destroyInternalData() override; /// check if initialized and except if it is not the case void checkInitialized(); /* ------------------------------------------------------------------------ */ /* 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/synchronizer/communication_request.hh b/src/synchronizer/communication_request.hh index ba9c858cb..f93ba330c 100644 --- a/src/synchronizer/communication_request.hh +++ b/src/synchronizer/communication_request.hh @@ -1,111 +1,113 @@ /** * @file real_static_communicator.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 * @date last modification: Wed Jan 13 2016 * * @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) * * Akantu is free 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 "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/communications_tmpl.hh b/src/synchronizer/communications_tmpl.hh index 6b07dae12..badefca03 100644 --- a/src/synchronizer/communications_tmpl.hh +++ b/src/synchronizer/communications_tmpl.hh @@ -1,560 +1,560 @@ /** * @file communications_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Tue Sep 6 17:14:06 2016 * * @brief Implementation of Communications * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communications.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_TMPL_HH__ #define __AKANTU_COMMUNICATIONS_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class Entity> class Communications<Entity>::iterator { typedef typename std::map<UInt, Communication>::iterator communication_iterator; public: - iterator() : communications(NULL) {} + 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 { typedef std::map<SynchronizationTag, UInt>::const_iterator internal_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) { scheme_iterator it = this->schemes[sr].begin(); scheme_iterator 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> Communications<Entity>::Communications(const Communicator & communicator) : communicator(communicator) {} /* ---------------------------------------------------------------------- */ // template <class Entity> // typename Communications<Entity>::iterator // Communications<Entity>::begin_send(const SynchronizationTag & tag) { // return this->begin(tag, _send); // } // template <class Entity> // typename Communications<Entity>::iterator // Communications<Entity>::end_send(const SynchronizationTag & tag) { // return this->end(tag, _send); // } // /* ---------------------------------------------------------------------- */ // template <class Entity> // typename Communications<Entity>::iterator // Communications<Entity>::begin_recv(const SynchronizationTag & tag) { // return this->begin(tag, _recv); // } // template <class Entity> // typename Communications<Entity>::iterator // Communications<Entity>::end_recv(const SynchronizationTag & tag) { // return this->end(tag, _recv); // } /* -------------------------------------------------------------------------- */ 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.hh b/src/synchronizer/communicator.hh index 4ece11d46..900b6b0dd 100644 --- a/src/synchronizer/communicator.hh +++ b/src/synchronizer/communicator.hh @@ -1,456 +1,456 @@ /** * @file static_communicator.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Jan 19 2016 * * @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) * * Akantu is free 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 "aka_array.hh" #include "aka_common.hh" #include "aka_event_handler_manager.hh" #include "communication_buffer.hh" #include "communication_request.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; struct FinalizeCommunicatorEvent { explicit FinalizeCommunicatorEvent(const Communicator & comm) : communicator(comm) {} const Communicator & communicator; }; class CommunicatorEventHandler { public: virtual ~CommunicatorEventHandler() {} virtual void onCommunicatorFinalize() {} private: inline void sendEvent(const FinalizeCommunicatorEvent &) { onCommunicatorFinalize(); } template <class EventHandler> friend class EventHandlerManager; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ class Communicator : public EventHandlerManager<CommunicatorEventHandler> { struct private_member {}; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Communicator(int & argc, char **& argv, const private_member &); - virtual ~Communicator(); + ~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, 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, 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_mpi_inline_impl.cc b/src/synchronizer/communicator_mpi_inline_impl.cc index a5e72fe98..9c3cf04ee 100644 --- a/src/synchronizer/communicator_mpi_inline_impl.cc +++ b/src/synchronizer/communicator_mpi_inline_impl.cc @@ -1,465 +1,465 @@ /** * @file static_communicator_mpi.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sun Sep 26 2010 * @date last modification: Thu Jan 21 2016 * * @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) * * Akantu is free 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 "aka_iterators.hh" #include "communicator.hh" #include "mpi_communicator_data.hh" /* -------------------------------------------------------------------------- */ #include <type_traits> #include <unordered_map> #include <vector> #include <memory> /* -------------------------------------------------------------------------- */ #include <mpi.h> /* -------------------------------------------------------------------------- */ #if (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if 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(); CommunicationRequestMPI * 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(); CommunicationRequestMPI * 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; CommunicationRequestMPI & 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; CommunicationRequestMPI & 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(); CommunicationRequestMPI * 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 = NULL, *recv_buf = NULL; + 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 = NULL, *recv_buf = NULL; + 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.hh b/src/synchronizer/data_accessor.hh index 6ef63932a..16cfab1e9 100644 --- a/src/synchronizer/data_accessor.hh +++ b/src/synchronizer/data_accessor.hh @@ -1,281 +1,279 @@ /** * @file data_accessor.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 01 2010 * @date last modification: Tue Dec 08 2015 * * @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) * * Akantu is free 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 "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() {} virtual ~DataAccessorBase() {} }; template <class T> class DataAccessor : public virtual DataAccessorBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DataAccessor() {} - virtual ~DataAccessor() {} + ~DataAccessor() override {} /* ------------------------------------------------------------------------ */ /* 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() {} - virtual ~DataAccessor() {} + ~DataAccessor() override {} 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() {} - virtual ~DataAccessor() {} + ~DataAccessor() override {} 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) {} - virtual ~ReduceUIntDataAccessor() {} + ~ReduceUIntDataAccessor() override {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ - virtual UInt getNbData(const Array<UInt> & elements, - const SynchronizationTag & tag) const { + 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); } /* ------------------------------------------------------------------------ */ - virtual void packData(CommunicationBuffer & buffer, - const Array<UInt> & elements, - const SynchronizationTag & tag) const { + 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]); } } /* ------------------------------------------------------------------------ */ - virtual void unpackData(CommunicationBuffer & buffer, - const Array<UInt> & elements, - const SynchronizationTag & tag) { + 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.hh b/src/synchronizer/dof_synchronizer.hh index 9e1eeb9a7..da02089fe 100644 --- a/src/synchronizer/dof_synchronizer.hh +++ b/src/synchronizer/dof_synchronizer.hh @@ -1,113 +1,116 @@ /** * @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 * * @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) * * Akantu is free 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 "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, const Communicator & comm = Communicator::getStaticCommunicator()); - virtual ~DOFSynchronizer(); + ~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 override final { AKANTU_DEBUG_TO_IMPLEMENT(); } + Int getRank(const UInt & /*node*/) const final { + AKANTU_DEBUG_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/element_synchronizer.hh b/src/synchronizer/element_synchronizer.hh index 55d838646..103ddd79e 100644 --- a/src/synchronizer/element_synchronizer.hh +++ b/src/synchronizer/element_synchronizer.hh @@ -1,210 +1,210 @@ /** * @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 * * @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) * * Akantu is free 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/>. * */ /* -------------------------------------------------------------------------- */ #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); public: - virtual ~ElementSynchronizer(); + ~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 */ /* ------------------------------------------------------------------------ */ - virtual UInt sanityCheckDataSize(const Array<Element> & elements, - const SynchronizationTag & tag) const; + UInt sanityCheckDataSize(const Array<Element> & elements, + const SynchronizationTag & tag) const override; /* ------------------------------------------------------------------------ */ - virtual void - packSanityCheckData(CommunicationDescriptor<Element> & comm_desc) const; + void + packSanityCheckData(CommunicationDescriptor<Element> & comm_desc) const override; /* ------------------------------------------------------------------------ */ - virtual void - unpackSanityCheckData(CommunicationDescriptor<Element> & comm_desc) const; + void + unpackSanityCheckData(CommunicationDescriptor<Element> & comm_desc) const override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Mesh, mesh, Mesh &); - Int getRank(const Element & element) const override final; + Int getRank(const Element & element) const final; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// reference to the underlying mesh Mesh & mesh; friend class FilteredSynchronizer; friend class FacetSynchronizer; ElementTypeMapArray<Int> element_to_prank; }; /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_ELEMENT_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/grid_synchronizer.hh b/src/synchronizer/grid_synchronizer.hh index 379e017d4..1005d0654 100644 --- a/src/synchronizer/grid_synchronizer.hh +++ b/src/synchronizer/grid_synchronizer.hh @@ -1,103 +1,103 @@ /** * @file grid_synchronizer.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Dec 08 2015 * * @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) * * Akantu is free 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 "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); - virtual ~GridSynchronizer() = default; + ~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/mpi_communicator_data.hh b/src/synchronizer/mpi_communicator_data.hh index 2a2b2e6bc..2b0222e90 100644 --- a/src/synchronizer/mpi_communicator_data.hh +++ b/src/synchronizer/mpi_communicator_data.hh @@ -1,136 +1,136 @@ /** * @file mpi_type_wrapper.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 * @date last modification: Wed Oct 07 2015 * * @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) * * Akantu is free 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 #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() { int is_initialized = false; MPI_Initialized(&is_initialized); if (!is_initialized) { - MPI_Init(NULL, NULL); // valid according to the spec + MPI_Init(nullptr, nullptr); // valid according to the spec } MPI_Comm_create_errhandler(MPICommunicatorData::errorHandler, &error_handler); setMPICommunicator(MPI_COMM_WORLD); is_externaly_initialized = is_initialized; } - ~MPICommunicatorData() { + ~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}; bool is_externaly_initialized{false}; /* ------------------------------------------------------------------------ */ 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.hh b/src/synchronizer/node_info_per_processor.hh index 9a28d965b..e75fcafd7 100644 --- a/src/synchronizer/node_info_per_processor.hh +++ b/src/synchronizer/node_info_per_processor.hh @@ -1,110 +1,110 @@ /** * @file node_info_per_processor.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Fri Mar 11 14:45:15 2016 * * @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) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "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(); - void synchronizeTypes(); - void synchronizeGroups(); + 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(); - void synchronizeTypes(); - void synchronizeGroups(); + 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.hh b/src/synchronizer/node_synchronizer.hh index 45d42b786..8bfd76044 100644 --- a/src/synchronizer/node_synchronizer.hh +++ b/src/synchronizer/node_synchronizer.hh @@ -1,86 +1,88 @@ /** * @file node_synchronizer.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Fri Sep 23 11:45:24 2016 * * @brief Synchronizer for nodal information * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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); - virtual ~NodeSynchronizer(); + ~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 override final { AKANTU_DEBUG_TO_IMPLEMENT(); } + Int getRank(const UInt & /*node*/) const final { + AKANTU_DEBUG_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/synchronizer.hh b/src/synchronizer/synchronizer.hh index 1f15397f1..2fad3305a 100644 --- a/src/synchronizer/synchronizer.hh +++ b/src/synchronizer/synchronizer.hh @@ -1,130 +1,130 @@ /** * @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 * * @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) * * Akantu is free 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 "aka_memory.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_HH__ #define __AKANTU_SYNCHRONIZER_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Base class for synchronizers */ /* -------------------------------------------------------------------------- */ class Synchronizer : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Synchronizer(const ID & id = "synchronizer", MemoryID memory_id = 0, const Communicator & comm = Communicator::getStaticCommunicator()); - virtual ~Synchronizer(){}; + ~Synchronizer() override{}; virtual void printself(__attribute__((unused)) std::ostream & stream, __attribute__((unused)) int indent = 0) const {}; /* ------------------------------------------------------------------------ */ /* 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; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Synchronizer & _this) { _this.printself(stream); return stream; } } // akantu #include "synchronizer_tmpl.hh" #endif /* __AKANTU_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/synchronizer_impl.hh b/src/synchronizer/synchronizer_impl.hh index a8cfdfea4..1b28e3583 100644 --- a/src/synchronizer/synchronizer_impl.hh +++ b/src/synchronizer/synchronizer_impl.hh @@ -1,122 +1,122 @@ /** * @file synchronizer_impl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Aug 24 13:26:47 2016 * * @brief Implementation of the generic part of synchronizers * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <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 ID & id = "synchronizer", MemoryID memory_id = 0, const Communicator & comm = Communicator::getStaticCommunicator()); - virtual ~SynchronizerImpl(){}; + ~SynchronizerImpl() override{}; /* ------------------------------------------------------------------------ */ /* 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; }; } // akantu #include "synchronizer_impl_tmpl.hh" #endif /* __AKANTU_SYNCHRONIZER_IMPL_HH__ */ diff --git a/src/synchronizer/synchronizer_registry.cc b/src/synchronizer/synchronizer_registry.cc index 0c8ce1398..38c318c89 100644 --- a/src/synchronizer/synchronizer_registry.cc +++ b/src/synchronizer/synchronizer_registry.cc @@ -1,139 +1,139 @@ /** * @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 * * @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) * * Akantu is free 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 "synchronizer_registry.hh" #include "synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SynchronizerRegistry::SynchronizerRegistry() : data_accessor(nullptr) { 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 != NULL, "No data accessor set."); + AKANTU_DEBUG_ASSERT(data_accessor != nullptr, "No data accessor set."); std::pair<Tag2Sync::iterator, Tag2Sync::iterator> range = synchronizers.equal_range(tag); for (Tag2Sync::iterator 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 != NULL, "No data accessor set."); + AKANTU_DEBUG_ASSERT(data_accessor != nullptr, "No data accessor set."); std::pair<Tag2Sync::iterator, Tag2Sync::iterator> range = synchronizers.equal_range(tag); for (Tag2Sync::iterator 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 != NULL, "No data accessor set."); + AKANTU_DEBUG_ASSERT(data_accessor != nullptr, "No data accessor set."); std::pair<Tag2Sync::iterator, Tag2Sync::iterator> range = synchronizers.equal_range(tag); for (Tag2Sync::iterator 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(); } /* -------------------------------------------------------------------------- */ void SynchronizerRegistry::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "SynchronizerRegistry [" << std::endl; Tag2Sync::const_iterator it; for (it = synchronizers.begin(); it != synchronizers.end(); it++) { stream << space << " + Synchronizers for tag " << (*it).first << " [" << std::endl; (*it).second->printself(stream, indent + 1); stream << space << " ]" << std::endl; } stream << space << "]" << std::endl; } } // akantu diff --git a/test/test_mesh_utils/test_segment_nodetype/test_segment_nodetype.cc b/test/test_mesh_utils/test_segment_nodetype/test_segment_nodetype.cc index bdd4aece5..8c696153e 100644 --- a/test/test_mesh_utils/test_segment_nodetype/test_segment_nodetype.cc +++ b/test/test_mesh_utils/test_segment_nodetype/test_segment_nodetype.cc @@ -1,97 +1,97 @@ /** * @file test_segment_nodetype.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Sep 18 2015 * * @brief Test to verify that the node type is correctly associated to * the segments in parallel * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char * argv[]) { initialize(argc, argv); UInt spatial_dimension = 3; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); // partition the mesh if (prank == 0) { mesh.read("mesh.msh"); } mesh.distribute(); // compute the node types for each segment Mesh & mesh_facets = mesh.initMeshFacets(); MeshUtils::buildSegmentToNodeType(mesh, mesh_facets); // verify that the number of segments per node type makes sense std::map<Int, UInt> nb_facets_per_nodetype; UInt nb_segments = 0; for (auto ghost_type : ghost_types) { const Array<Int> & segment_to_nodetype = mesh_facets.getData<Int>("segment_to_nodetype", _segment_2, ghost_type); // count the number of segments per node type for (auto & stn : segment_to_nodetype) { if (nb_facets_per_nodetype.find(stn) == nb_facets_per_nodetype.end()) nb_facets_per_nodetype[stn] = 1; else ++nb_facets_per_nodetype[stn]; } nb_segments += segment_to_nodetype.size(); } // checking the solution if (nb_segments != 24) AKANTU_DEBUG_ERROR("The number of segments is wrong"); if (prank == 0) { if (nb_facets_per_nodetype[-1] != 3 || nb_facets_per_nodetype[-2] != 9 || nb_facets_per_nodetype[-3] != 12) AKANTU_DEBUG_ERROR( "The segments of processor 0 have the wrong node type"); if (nb_facets_per_nodetype.size() > 3) AKANTU_DEBUG_ERROR("Processor 0 cannot have any slave segment"); } if (prank == psize - 1 && nb_facets_per_nodetype.find(-2) != nb_facets_per_nodetype.end()) AKANTU_DEBUG_ERROR("The last processor must not have any master facets"); finalize(); return 0; } diff --git a/test/test_model/test_model_solver/test_model_solver_my_model.hh b/test/test_model/test_model_solver/test_model_solver_my_model.hh index 58fc2a0e9..9490b1a10 100644 --- a/test/test_model/test_model_solver/test_model_solver_my_model.hh +++ b/test/test_model/test_model_solver/test_model_solver_my_model.hh @@ -1,468 +1,468 @@ /** * @file test_dof_manager_default.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Feb 24 12:28:44 2016 * * @brief Test default dof manager * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "data_accessor.hh" #include "dof_manager_default.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "model_solver.hh" #include "sparse_matrix.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ namespace akantu { #ifndef __AKANTU_TEST_MODEL_SOLVER_MY_MODEL_HH__ #define __AKANTU_TEST_MODEL_SOLVER_MY_MODEL_HH__ /** * =\o-----o-----o-> F * | | * |---- L ----| */ class MyModel : public ModelSolver, public DataAccessor<Element> { public: MyModel(Real F, Mesh & mesh, bool lumped) : ModelSolver(mesh, "model_solver", 0), nb_dofs(mesh.getNbNodes()), nb_elements(mesh.getNbElement()), E(1.), A(1.), rho(1.), lumped(lumped), mesh(mesh), displacement(nb_dofs, 1, "disp"), velocity(nb_dofs, 1, "velo"), acceleration(nb_dofs, 1, "accel"), blocked(nb_dofs, 1, "blocked"), forces(nb_dofs, 1, "force_ext"), internal_forces(nb_dofs, 1, "force_int"), stresses(nb_elements, 1, "stress"), strains(nb_elements, 1, "strain"), initial_lengths(nb_elements, 1, "L0") { this->initDOFManager(); this->getDOFManager().registerDOFs("disp", displacement, _dst_nodal); this->getDOFManager().registerDOFsDerivative("disp", 1, velocity); this->getDOFManager().registerDOFsDerivative("disp", 2, acceleration); this->getDOFManager().registerBlockedDOFs("disp", blocked); displacement.set(0.); velocity.set(0.); acceleration.set(0.); forces.set(0.); blocked.set(false); UInt global_nb_nodes = mesh.getNbGlobalNodes(); for (auto && n : arange(nb_dofs)) { auto global_id = mesh.getNodeGlobalId(n); if (global_id == (global_nb_nodes - 1)) forces(n, _x) = F; if (global_id == 0) blocked(n, _x) = true; } auto cit = this->mesh.getConnectivity(_segment_2).begin(2); auto cend = this->mesh.getConnectivity(_segment_2).end(2); auto L_it = this->initial_lengths.begin(); for (; cit != cend; ++cit, ++L_it) { const Vector<UInt> & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); *L_it = std::abs(p2 - p1); } this->registerDataAccessor(*this); this->registerSynchronizer( const_cast<ElementSynchronizer &>(this->mesh.getElementSynchronizer()), _gst_user_1); } void assembleLumpedMass() { Array<Real> & M = this->getDOFManager().getLumpedMatrix("M"); M.clear(); this->assembleLumpedMass(_not_ghost); if (this->mesh.getNbElement(_segment_2, _ghost) > 0) this->assembleLumpedMass(_ghost); is_lumped_mass_assembled = true; } void assembleLumpedMass(const GhostType & ghost_type) { Array<Real> & M = this->getDOFManager().getLumpedMatrix("M"); Array<Real> m_all_el(this->mesh.getNbElement(_segment_2, ghost_type), 2); Array<Real>::vector_iterator m_it = m_all_el.begin(2); auto cit = this->mesh.getConnectivity(_segment_2, ghost_type).begin(2); auto cend = this->mesh.getConnectivity(_segment_2, ghost_type).end(2); for (; cit != cend; ++cit, ++m_it) { const Vector<UInt> & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); Real L = std::abs(p2 - p1); Real M_n = rho * A * L / 2; (*m_it)(0) = (*m_it)(1) = M_n; } this->getDOFManager().assembleElementalArrayLocalArray( m_all_el, M, _segment_2, ghost_type); } void assembleMass() { SparseMatrix & M = this->getDOFManager().getMatrix("M"); M.clear(); Array<Real> m_all_el(this->nb_elements, 4); Array<Real>::matrix_iterator m_it = m_all_el.begin(2, 2); auto cit = this->mesh.getConnectivity(_segment_2).begin(2); auto cend = this->mesh.getConnectivity(_segment_2).end(2); Matrix<Real> m(2, 2); m(0, 0) = m(1, 1) = 2; m(0, 1) = m(1, 0) = 1; // under integrated // m(0, 0) = m(1, 1) = 3./2.; // m(0, 1) = m(1, 0) = 3./2.; // lumping the mass matrix // m(0, 0) += m(0, 1); // m(1, 1) += m(1, 0); // m(0, 1) = m(1, 0) = 0; for (; cit != cend; ++cit, ++m_it) { const Vector<UInt> & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); Real L = std::abs(p2 - p1); Matrix<Real> & m_el = *m_it; m_el = m; m_el *= rho * A * L / 6.; } this->getDOFManager().assembleElementalMatricesToMatrix( "M", "disp", m_all_el, _segment_2); is_mass_assembled = true; } MatrixType getMatrixType(const ID &) { return _symmetric; } void assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { if (not is_stiffness_assembled) this->assembleStiffness(); } else if (matrix_id == "M") { if (not is_mass_assembled) this->assembleMass(); } else if (matrix_id == "C") { // pass, no damping matrix } else { AKANTU_EXCEPTION("This solver does not know what to do with a matrix " << matrix_id); } } void assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { if (not is_lumped_mass_assembled) this->assembleLumpedMass(); } else { AKANTU_EXCEPTION("This solver does not know what to do with a matrix " << matrix_id); } } void assembleStiffness() { SparseMatrix & K = this->getDOFManager().getMatrix("K"); K.clear(); Matrix<Real> k(2, 2); k(0, 0) = k(1, 1) = 1; k(0, 1) = k(1, 0) = -1; Array<Real> k_all_el(this->nb_elements, 4); auto k_it = k_all_el.begin(2, 2); auto cit = this->mesh.getConnectivity(_segment_2).begin(2); auto cend = this->mesh.getConnectivity(_segment_2).end(2); for (; cit != cend; ++cit, ++k_it) { const auto & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); Real L = std::abs(p2 - p1); auto & k_el = *k_it; k_el = k; k_el *= E * A / L; } this->getDOFManager().assembleElementalMatricesToMatrix( "K", "disp", k_all_el, _segment_2); is_stiffness_assembled = true; } void assembleResidual() { this->getDOFManager().assembleToResidual("disp", forces); internal_forces.clear(); this->assembleResidual(_not_ghost); this->synchronize(_gst_user_1); this->getDOFManager().assembleToResidual("disp", internal_forces, -1.); - // auto & comm = StaticCommunicator::getStaticCommunicator(); + // auto & comm = Communicator::getStaticCommunicator(); // const auto & dof_manager_default = // dynamic_cast<DOFManagerDefault &>(this->getDOFManager()); // const auto & residual = dof_manager_default.getResidual(); // int prank = comm.whoAmI(); // int psize = comm.getNbProc(); // for (int p = 0; p < psize; ++p) { // if (prank == p) { // UInt local_dof = 0; // for (auto res : residual) { // UInt global_dof = // dof_manager_default.localToGlobalEquationNumber(local_dof); // std::cout << local_dof << " [" << global_dof << " - " // << dof_manager_default.getDOFType(local_dof) << "]: " << // res // << std::endl; // ++local_dof; // } // std::cout << std::flush; // } // comm.barrier(); // } // comm.barrier(); // if(prank == 0) std::cout << "===========================" << std::endl; } void assembleResidual(const GhostType & ghost_type) { Array<Real> forces_internal_el( this->mesh.getNbElement(_segment_2, ghost_type), 2); auto cit = this->mesh.getConnectivity(_segment_2, ghost_type).begin(2); auto cend = this->mesh.getConnectivity(_segment_2, ghost_type).end(2); auto f_it = forces_internal_el.begin(2); auto strain_it = this->strains.begin(); auto stress_it = this->stresses.begin(); auto L_it = this->initial_lengths.begin(); for (; cit != cend; ++cit, ++f_it, ++strain_it, ++stress_it, ++L_it) { const auto & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real u1 = this->displacement(n1, _x); Real u2 = this->displacement(n2, _x); *strain_it = (u2 - u1) / *L_it; *stress_it = E * *strain_it; Real f_n = A * *stress_it; Vector<Real> & f = *f_it; f(0) = -f_n; f(1) = f_n; } this->getDOFManager().assembleElementalArrayLocalArray( forces_internal_el, internal_forces, _segment_2, ghost_type); } Real getPotentialEnergy() { Real res = 0; if (!lumped) { res = this->mulVectMatVect(this->displacement, this->getDOFManager().getMatrix("K"), this->displacement); } else { auto strain_it = this->strains.begin(); auto stress_it = this->stresses.begin(); auto strain_end = this->strains.end(); auto L_it = this->initial_lengths.begin(); for (; strain_it != strain_end; ++strain_it, ++stress_it, ++L_it) { res += *strain_it * *stress_it * A * *L_it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); } return res / 2.; } Real getKineticEnergy() { Real res = 0; if (!lumped) { res = this->mulVectMatVect( this->velocity, this->getDOFManager().getMatrix("M"), this->velocity); } else { auto & m = this->getDOFManager().getLumpedMatrix("M"); auto it = velocity.begin(); auto end = velocity.end(); auto m_it = m.begin(); for (UInt node = 0; it != end; ++it, ++m_it, ++node) { if (mesh.isLocalOrMasterNode(node)) res += *m_it * *it * *it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); } return res / 2.; } Real getExternalWorkIncrement() { Real res = 0; auto it = velocity.begin(); auto end = velocity.end(); auto if_it = internal_forces.begin(); auto ef_it = forces.begin(); auto b_it = blocked.begin(); for (UInt node = 0; it != end; ++it, ++if_it, ++ef_it, ++b_it, ++node) { if (mesh.isLocalOrMasterNode(node)) res += (*b_it ? -*if_it : *ef_it) * *it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); return res * this->getTimeStep(); } Real mulVectMatVect(const Array<Real> & x, const SparseMatrix & A, const Array<Real> & y) { Array<Real> Ay(this->nb_dofs, 1, 0.); A.matVecMul(y, Ay); Real res = 0.; Array<Real>::const_scalar_iterator it = Ay.begin(); Array<Real>::const_scalar_iterator end = Ay.end(); Array<Real>::const_scalar_iterator x_it = x.begin(); for (UInt node = 0; it != end; ++it, ++x_it, ++node) { if (mesh.isLocalOrMasterNode(node)) res += *x_it * *it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); return res; } void predictor() {} void corrector() {} /* ------------------------------------------------------------------------ */ UInt getNbData(const Array<Element> & elements, const SynchronizationTag &) const { return elements.size() * sizeof(Real); } void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_user_1) { for (const auto & el : elements) { buffer << this->stresses(el.element); } } } void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_user_1) { auto cit = this->mesh.getConnectivity(_segment_2, _ghost).begin(2); for (const auto & el : elements) { Real stress; buffer >> stress; Real f = A * stress; Vector<UInt> conn = cit[el.element]; this->internal_forces(conn(0), _x) += -f; this->internal_forces(conn(1), _x) += f; } } } private: UInt nb_dofs; UInt nb_elements; Real E, A, rho; bool lumped; bool is_stiffness_assembled{false}; bool is_mass_assembled{false}; bool is_lumped_mass_assembled{false}; public: Mesh & mesh; Array<Real> displacement; Array<Real> velocity; Array<Real> acceleration; Array<bool> blocked; Array<Real> forces; Array<Real> internal_forces; Array<Real> stresses; Array<Real> strains; Array<Real> initial_lengths; }; #endif /* __AKANTU_TEST_MODEL_SOLVER_MY_MODEL_HH__ */ } // akantu diff --git a/test/test_model/test_non_local_toolbox/my_model.hh b/test/test_model/test_non_local_toolbox/my_model.hh index 458712eae..6304cf19c 100644 --- a/test/test_model/test_non_local_toolbox/my_model.hh +++ b/test/test_model/test_non_local_toolbox/my_model.hh @@ -1,118 +1,122 @@ /** * @file my_model.hh * * @author Nicolas Richart * * @date creation Sun Sep 10 2017 * * @brief A Documented file. * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "integrator_gauss.hh" #include "model.hh" #include "non_local_manager.hh" #include "non_local_manager_callback.hh" #include "non_local_neighborhood_base.hh" #include "shape_lagrange.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; class MyModel : public Model, public NonLocalManagerCallback { using MyFEEngineType = FEEngineTemplate<IntegratorGauss, ShapeLagrange>; public: MyModel(Mesh & mesh, UInt spatial_dimension) : Model(mesh, spatial_dimension), manager(*this, *this) { registerFEEngineObject<MyFEEngineType>("FEEngine", mesh, spatial_dimension); manager.registerNeighborhood("test_region", "test_region"); getFEEngine().initShapeFunctions(); manager.initialize(); } void initModel() override {} MatrixType getMatrixType(const ID &) override { return _mt_not_defined; } + std::tuple<ID, TimeStepSolverType> + getDefaultSolverID(const AnalysisMethod & /*method*/) { + return {"test", _tsst_static}; + } + void assembleMatrix(const ID &) override {} void assembleLumpedMatrix(const ID &) override {} void assembleResidual() override {} void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) override {} void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, const RemovedNodesEvent &) override {} 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 {} void insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type) override { 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); IntegrationPoint q; q.ghost_type = ghost_type; - q.kind = _ek_regular; q.global_num = 0; auto & neighborhood = manager.getNeighborhood("test_region"); for (auto & type : quadrature_points_coordinates.elementTypes( spatial_dimension, ghost_type)) { q.type = type; auto & quads = quadrature_points_coordinates(type, ghost_type); this->getFEEngine().computeIntegrationPointsCoordinates(quads, type, ghost_type); auto quad_it = quads.begin(quads.getNbComponent()); auto quad_end = quads.end(quads.getNbComponent()); q.num_point = 0; for (; quad_it != quad_end; ++quad_it) { neighborhood.insertIntegrationPoint(q, *quad_it); ++q.num_point; ++q.global_num; } } } void computeNonLocalStresses(const GhostType &) override {} void updateLocalInternal(ElementTypeMapReal &, const GhostType &, const ElementKind &) override {} void updateNonLocalInternal(ElementTypeMapReal &, const GhostType &, const ElementKind &) override {} const auto & getNonLocalManager() const { return manager; } private: NonLocalManager manager; }; diff --git a/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc index 756685754..c199735a3 100644 --- a/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc +++ b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc @@ -1,191 +1,191 @@ /** * @file test_build_neighborhood_parallel.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief test in parallel for the class NonLocalNeighborhood * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_paraview.hh" #include "non_local_neighborhood_base.hh" #include "solid_mechanics_model.hh" #include "test_material.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { akantu::initialize("material_parallel_test.dat", argc, argv); - auto & comm = akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); // some configuration variables const UInt spatial_dimension = 2; // mesh creation and read Mesh mesh(spatial_dimension); if (prank == 0) { mesh.read("parallel_test.msh"); } mesh.distribute(); /// model creation SolidMechanicsModel model(mesh); /// dump the ghost elements before the non-local part is intialized DumperParaview dumper_ghost("ghost_elements"); dumper_ghost.registerMesh(mesh, spatial_dimension, _ghost); if (psize > 1) { dumper_ghost.dump(); } /// creation of material selector MeshDataMaterialSelector<std::string> mat_selector("physical_names", model); model.setMaterialSelector(mat_selector); /// dump material index in paraview model.addDumpField("partitions"); model.dump(); /// model initialization changed to use our material model.initFull(); /// dump the ghost elements after ghosts for non-local have been added if (psize > 1) dumper_ghost.dump(); model.addDumpField("grad_u"); model.addDumpField("grad_u non local"); model.addDumpField("material_index"); /// apply constant strain field everywhere in the plate Matrix<Real> applied_strain(spatial_dimension, spatial_dimension); applied_strain.clear(); for (UInt i = 0; i < spatial_dimension; ++i) applied_strain(i, i) = 2.; ElementType element_type = _triangle_3; GhostType ghost_type = _not_ghost; /// apply constant grad_u field in all elements for (UInt m = 0; m < model.getNbMaterials(); ++m) { auto & mat = model.getMaterial(m); auto & grad_u = const_cast<Array<Real> &>( mat.getInternal<Real>("grad_u")(element_type, ghost_type)); auto grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); auto grad_u_end = grad_u.end(spatial_dimension, spatial_dimension); for (; grad_u_it != grad_u_end; ++grad_u_it) (*grad_u_it) = -1. * applied_strain; } /// double the strain in the center: find the closed gauss point to the center /// compute the quadrature points ElementTypeMapReal quad_coords("quad_coords"); quad_coords.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _with_nb_element = true); model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); Vector<Real> center(spatial_dimension, 0.); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_regular); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_regular); Real min_distance = 2; IntegrationPoint q_min; for (; it != last_type; ++it) { ElementType type = *it; UInt nb_elements = mesh.getNbElement(type, _not_ghost); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(type); Array<Real> & coords = quad_coords(type, _not_ghost); Array<Real>::const_vector_iterator coord_it = coords.begin(spatial_dimension); for (UInt e = 0; e < nb_elements; ++e) { for (UInt q = 0; q < nb_quads; ++q, ++coord_it) { Real dist = center.distance(*coord_it); if (dist < min_distance) { min_distance = dist; q_min.element = e; q_min.num_point = q; q_min.global_num = nb_elements * nb_quads + q; q_min.type = type; } } } } Real global_min = min_distance; - comm.allReduce(global_min, _so_min); + comm.allReduce(global_min, SynchronizerOperation::_min); if (Math::are_float_equal(global_min, min_distance)) { UInt mat_index = model.getMaterialByElement(q_min.type, _not_ghost) .begin()[q_min.element]; Material & mat = model.getMaterial(mat_index); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(q_min.type); UInt local_el_index = model.getMaterialLocalNumbering(q_min.type, _not_ghost) .begin()[q_min.element]; UInt local_num = (local_el_index * nb_quads) + q_min.num_point; Array<Real> & grad_u = const_cast<Array<Real> &>( mat.getInternal<Real>("grad_u")(q_min.type, _not_ghost)); Array<Real>::iterator<Matrix<Real>> grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); grad_u_it += local_num; Matrix<Real> & g_u = *grad_u_it; g_u += applied_strain; } /// compute the non-local strains model.assembleInternalForces(); model.dump(); /// damage the element with higher grad_u completely, so that it is /// not taken into account for the averaging if (Math::are_float_equal(global_min, min_distance)) { UInt mat_index = model.getMaterialByElement(q_min.type, _not_ghost) .begin()[q_min.element]; Material & mat = model.getMaterial(mat_index); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(q_min.type); UInt local_el_index = model.getMaterialLocalNumbering(q_min.type, _not_ghost) .begin()[q_min.element]; UInt local_num = (local_el_index * nb_quads) + q_min.num_point; Array<Real> & damage = const_cast<Array<Real> &>( mat.getInternal<Real>("damage")(q_min.type, _not_ghost)); Real * dam_ptr = damage.storage(); dam_ptr += local_num; *dam_ptr = 0.9; } /// compute the non-local strains model.assembleInternalForces(); model.dump(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_non_local_toolbox/test_pair_computation.cc b/test/test_model/test_non_local_toolbox/test_pair_computation.cc index 84207e7cb..d88839d3a 100644 --- a/test/test_model/test_non_local_toolbox/test_pair_computation.cc +++ b/test/test_model/test_non_local_toolbox/test_pair_computation.cc @@ -1,227 +1,224 @@ /** * @file test_pair_computation.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Wed Nov 25 2015 * * @brief test the weight computation with and without grid * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_paraview.hh" #include "non_local_manager.hh" #include "non_local_neighborhood.hh" #include "solid_mechanics_model.hh" #include "test_material_damage.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; typedef std::vector<std::pair<IntegrationPoint, IntegrationPoint>> PairList; /* -------------------------------------------------------------------------- */ void computePairs(SolidMechanicsModel & model, PairList * pair_list); int main(int argc, char * argv[]) { akantu::initialize("material_remove_damage.dat", argc, argv); // some configuration variables const UInt spatial_dimension = 2; - StaticCommunicator & comm = - akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); // mesh creation and read Mesh mesh(spatial_dimension); if (prank == 0) { mesh.read("pair_test.msh"); } mesh.distribute(); /// model creation SolidMechanicsModel model(mesh); /// creation of material selector MeshDataMaterialSelector<std::string> mat_selector("physical_names", model); model.setMaterialSelector(mat_selector); /// model initialization changed to use our material model.initFull(); /// dump material index in paraview model.addDumpField("material_index"); model.dump(); /// compute the pairs by looping over all the quadrature points PairList pair_list[2]; computePairs(model, pair_list); const PairList * pairs_mat_1 = model.getNonLocalManager().getNeighborhood("mat_1").getPairLists(); const PairList * pairs_mat_2 = model.getNonLocalManager().getNeighborhood("mat_2").getPairLists(); /// compare the number of pairs UInt nb_not_ghost_pairs_grid = pairs_mat_1[0].size() + pairs_mat_2[0].size(); UInt nb_ghost_pairs_grid = pairs_mat_1[1].size() + pairs_mat_2[1].size(); UInt nb_not_ghost_pairs_no_grid = pair_list[0].size(); UInt nb_ghost_pairs_no_grid = pair_list[1].size(); if ((nb_not_ghost_pairs_grid != nb_not_ghost_pairs_no_grid) || (nb_ghost_pairs_grid != nb_ghost_pairs_no_grid)) { std::cout << "The number of pairs is not correct: TEST FAILED!!!" << std::endl; finalize(); return EXIT_FAILURE; } for (UInt i = 0; i < pairs_mat_1[0].size(); ++i) { PairList::const_iterator it = std::find( pair_list[0].begin(), pair_list[0].end(), (pairs_mat_1[0])[i]); if (it == pair_list[0].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } for (UInt i = 0; i < pairs_mat_2[0].size(); ++i) { PairList::const_iterator it = std::find( pair_list[0].begin(), pair_list[0].end(), (pairs_mat_2[0])[i]); if (it == pair_list[0].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } for (UInt i = 0; i < pairs_mat_1[1].size(); ++i) { PairList::const_iterator it = std::find( pair_list[1].begin(), pair_list[1].end(), (pairs_mat_1[1])[i]); if (it == pair_list[1].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } for (UInt i = 0; i < pairs_mat_2[1].size(); ++i) { PairList::const_iterator it = std::find( pair_list[1].begin(), pair_list[1].end(), (pairs_mat_2[1])[i]); if (it == pair_list[1].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } finalize(); return 0; } /* -------------------------------------------------------------------------- */ void computePairs(SolidMechanicsModel & model, PairList * pair_list) { ElementKind kind = _ek_regular; Mesh & mesh = model.getMesh(); UInt spatial_dimension = model.getSpatialDimension(); /// compute the quadrature points ElementTypeMapReal quad_coords("quad_coords"); quad_coords.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _with_nb_element = true); model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); /// loop in a n^2 way over all the quads to generate the pairs Real neighborhood_radius = 0.5; Mesh::type_iterator it_1 = mesh.firstType(spatial_dimension, _not_ghost, kind); Mesh::type_iterator last_type_1 = mesh.lastType(spatial_dimension, _not_ghost, kind); IntegrationPoint q1; IntegrationPoint q2; - q1.kind = kind; - q2.kind = kind; GhostType ghost_type_1 = _not_ghost; q1.ghost_type = ghost_type_1; Vector<Real> q1_coords(spatial_dimension); Vector<Real> q2_coords(spatial_dimension); for (; it_1 != last_type_1; ++it_1) { ElementType type_1 = *it_1; q1.type = type_1; UInt nb_elements_1 = mesh.getNbElement(type_1, ghost_type_1); UInt nb_quads_1 = model.getFEEngine().getNbIntegrationPoints(type_1); Array<Real> & quad_coords_1 = quad_coords(q1.type, q1.ghost_type); Array<Real>::const_vector_iterator coord_it_1 = quad_coords_1.begin(spatial_dimension); for (UInt e_1 = 0; e_1 < nb_elements_1; ++e_1) { q1.element = e_1; UInt mat_index_1 = model.getMaterialByElement(q1.type, q1.ghost_type) .begin()[q1.element]; for (UInt q_1 = 0; q_1 < nb_quads_1; ++q_1) { q1.global_num = nb_quads_1 * e_1 + q_1; q1.num_point = q_1; q1_coords = coord_it_1[q1.global_num]; /// loop over all other quads and create pairs for this given quad for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type_2 = *gt; q2.ghost_type = ghost_type_2; Mesh::type_iterator it_2 = mesh.firstType(spatial_dimension, ghost_type_2, kind); Mesh::type_iterator last_type_2 = mesh.lastType(spatial_dimension, ghost_type_2, kind); for (; it_2 != last_type_2; ++it_2) { ElementType type_2 = *it_2; q2.type = type_2; UInt nb_elements_2 = mesh.getNbElement(type_2, ghost_type_2); UInt nb_quads_2 = model.getFEEngine().getNbIntegrationPoints(type_2); Array<Real> & quad_coords_2 = quad_coords(q2.type, q2.ghost_type); Array<Real>::const_vector_iterator coord_it_2 = quad_coords_2.begin(spatial_dimension); for (UInt e_2 = 0; e_2 < nb_elements_2; ++e_2) { q2.element = e_2; UInt mat_index_2 = model.getMaterialByElement(q2.type, q2.ghost_type) .begin()[q2.element]; for (UInt q_2 = 0; q_2 < nb_quads_2; ++q_2) { q2.global_num = nb_quads_2 * e_2 + q_2; q2.num_point = q_2; q2_coords = coord_it_2[q2.global_num]; Real distance = q1_coords.distance(q2_coords); if (mat_index_1 != mat_index_2) continue; else if (distance <= 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)); } } } } } } } } } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc index 1a32681bf..a9a04a914 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc @@ -1,205 +1,205 @@ /** * @file test_cohesive_facet_stress_synchronizer.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Test for facet stress synchronizer * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include <limits> #include <fstream> #include <iostream> /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; Real function(Real constant, Real x, Real y, Real z) { return constant + 2. * x + 3. * y + 4 * z; } int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); const UInt spatial_dimension = 3; ElementType type = _tetrahedron_10; ElementType type_facet = Mesh::getFacetType(type); Math::setTolerance(1.e-11); Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("tetrahedron.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); model.initFull(SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); Array<Real> & position = mesh.getNodes(); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ /// compute quadrature points positions on facets const Mesh & mesh_facets = model.getMeshFacets(); UInt nb_facet = mesh_facets.getNbElement(type_facet); UInt nb_quad_per_facet = model.getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); UInt nb_tot_quad = nb_quad_per_facet * nb_facet; Array<Real> quad_facets(nb_tot_quad, spatial_dimension); model.getFEEngine("FacetsFEEngine").interpolateOnIntegrationPoints(position, quad_facets, spatial_dimension, type_facet); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ /// compute quadrature points position of the elements UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); UInt nb_element = mesh.getNbElement(type); UInt nb_tot_quad_el = nb_quad_per_element * nb_element; Array<Real> quad_elements(nb_tot_quad_el, spatial_dimension); model.getFEEngine().interpolateOnIntegrationPoints(position, quad_elements, spatial_dimension, type); /// assign some values to stresses Array<Real> & stress = const_cast<Array<Real>&>(model.getMaterial(0).getStress(type)); Array<Real>::iterator<Matrix<Real> > stress_it = stress.begin(spatial_dimension, spatial_dimension); for (UInt q = 0; q < nb_tot_quad_el; ++q, ++stress_it) { /// compute values for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = i; j < spatial_dimension; ++j) { UInt index = i * spatial_dimension + j; (*stress_it)(i, j) = function(index, quad_elements(q, 0), quad_elements(q, 1), quad_elements(q, 2)); } } /// fill symmetrical part for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < i; ++j) { (*stress_it)(i, j) = (*stress_it)(j, i); } } // stress_it->clear(); // for (UInt i = 0; i < spatial_dimension; ++i) // (*stress_it)(i, i) = sigma_c * 5; } /// compute and communicate stress on facets model.checkCohesiveStress(); /* ------------------------------------------------------------------------ */ /* Check facet stress */ /* ------------------------------------------------------------------------ */ const Array<Real> & facet_stress = model.getStressOnFacets(type_facet); const Array<bool> & facet_check = model.getElementInserter().getCheckFacets(type_facet); const Array<std::vector<Element> > & elements_to_facet = model.getMeshFacets().getElementToSubelement(type_facet); Array<Real>::iterator<Vector<Real> > quad_facet_it = quad_facets.begin(spatial_dimension); Array<Real>::const_iterator<Matrix<Real> > facet_stress_it = facet_stress.begin(spatial_dimension, spatial_dimension * 2); Matrix<Real> current_stress(spatial_dimension, spatial_dimension); for (UInt f = 0; f < nb_facet; ++f) { if (!facet_check(f) || (elements_to_facet(f)[0].ghost_type == _not_ghost && elements_to_facet(f)[1].ghost_type == _not_ghost)) { quad_facet_it += nb_quad_per_facet; facet_stress_it += nb_quad_per_facet; continue; } for (UInt q = 0; q < nb_quad_per_facet; ++q, ++quad_facet_it, ++facet_stress_it) { /// compute current_stress for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = i; j < spatial_dimension; ++j) { UInt index = i * spatial_dimension + j; current_stress(i, j) = function(index, (*quad_facet_it)(0), (*quad_facet_it)(1), (*quad_facet_it)(2)); } } /// fill symmetrical part for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < i; ++j) { current_stress(i, j) = current_stress(j, i); } } /// compare it to interpolated one for (UInt s = 0; s < 2; ++s) { Matrix<Real> stress_to_check(facet_stress_it->storage() + s * spatial_dimension * spatial_dimension, spatial_dimension, spatial_dimension); for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { if (!Math::are_float_equal(stress_to_check(i, j), current_stress(i, j))) { std::cout << "Stress doesn't match" << std::endl; finalize(); return EXIT_FAILURE; } } } } } } finalize(); if (prank == 0) std::cout << "OK: test_cohesive_facet_stress_synchronizer passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc index 0484a2351..f80e75f54 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc @@ -1,432 +1,432 @@ /** * @file test_cohesive_parallel_buildfragments.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Test to build fragments in parallel * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include <limits> #include <fstream> #include <iostream> #include <algorithm> #include <functional> /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "material_cohesive.hh" #include "fragment_manager.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; void verticalInsertionLimit(SolidMechanicsModelCohesive &); void displaceElements(SolidMechanicsModelCohesive &, const Real, const Real); bool isInertiaEqual(const Vector<Real> &, const Vector<Real> &); void rotateArray(Array<Real> & array, Real angle); UInt getNbBigFragments(FragmentManager &, UInt); const UInt spatial_dimension = 3; const UInt total_nb_fragment = 4; const Real rotation_angle = M_PI / 4.; const Real global_tolerance = 1.e-9; int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); Math::setTolerance(global_tolerance); Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("mesh.msh"); /// partition the mesh MeshUtils::purifyMesh(mesh); partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); delete partition; /// model initialization model.initFull(SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); mesh.computeBoundingBox(); Real L = mesh.getUpperBounds()(0) - mesh.getLowerBounds()(0); Real h = mesh.getUpperBounds()(1) - mesh.getLowerBounds()(1); Real rho = model.getMaterial("bulk").getParam<Real>("rho"); Real theoretical_mass = L * h * h * rho; Real frag_theo_mass = theoretical_mass / total_nb_fragment; UInt nb_element = mesh.getNbElement(spatial_dimension, _not_ghost, _ek_regular); comm.allReduce(&nb_element, 1, _so_sum); UInt nb_element_per_fragment = nb_element / total_nb_fragment; FragmentManager fragment_manager(model); fragment_manager.computeAllData(); getNbBigFragments(fragment_manager, nb_element_per_fragment + 1); model.setBaseName("extrinsic"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity"); model.addDumpField("stress"); model.addDumpField("partitions"); model.addDumpField("fragments"); model.addDumpField("fragments mass"); model.addDumpField("moments of inertia"); model.addDumpField("elements per fragment"); model.dump(); model.setBaseNameToDumper("cohesive elements", "cohesive_elements_test"); model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.addDumpFieldToDumper("cohesive elements", "damage"); model.dump("cohesive elements"); /// set check facets verticalInsertionLimit(model); model.assembleMassLumped(); model.synchronizeBoundaries(); /// impose initial displacement Array<Real> & displacement = model.getDisplacement(); Array<Real> & velocity = model.getVelocity(); const Array<Real> & position = mesh.getNodes(); UInt nb_nodes = mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { displacement(n, 0) = position(n, 0) * 0.1; velocity(n, 0) = position(n, 0); } rotateArray(mesh.getNodes(), rotation_angle); // rotateArray(displacement, rotation_angle); // rotateArray(velocity, rotation_angle); model.updateResidual(); model.checkCohesiveStress(); model.dump(); model.dump("cohesive elements"); const Array<Real> & fragment_mass = fragment_manager.getMass(); const Array<Real> & fragment_center = fragment_manager.getCenterOfMass(); Real el_size = L / total_nb_fragment; Real lim = -L/2 + el_size * 0.99; /// define theoretical inertia moments Vector<Real> small_frag_inertia(spatial_dimension); small_frag_inertia(0) = frag_theo_mass * (h*h + h*h) / 12.; small_frag_inertia(1) = frag_theo_mass * (el_size*el_size + h*h) / 12.; small_frag_inertia(2) = frag_theo_mass * (el_size*el_size + h*h) / 12.; std::sort(small_frag_inertia.storage(), small_frag_inertia.storage() + spatial_dimension, std::greater<Real>()); const Array<Real> & inertia_moments = fragment_manager.getMomentsOfInertia(); Array<Real>::const_iterator< Vector<Real> > inertia_moments_begin = inertia_moments.begin(spatial_dimension); /// displace one fragment each time for (UInt frag = 1; frag <= total_nb_fragment; ++frag) { if (prank == 0) std::cout << "Generating fragment: " << frag << std::endl; fragment_manager.computeAllData(); /// check number of big fragments UInt nb_big_fragment = getNbBigFragments(fragment_manager, nb_element_per_fragment + 1); model.dump(); model.dump("cohesive elements"); if (frag < total_nb_fragment) { if (nb_big_fragment != 1) { AKANTU_DEBUG_ERROR("The number of big fragments is wrong: " << nb_big_fragment); return EXIT_FAILURE; } } else { if (nb_big_fragment != 0) { AKANTU_DEBUG_ERROR("The number of big fragments is wrong: " << nb_big_fragment); return EXIT_FAILURE; } } /// check number of fragments UInt nb_fragment_num = fragment_manager.getNbFragment(); if (nb_fragment_num != frag) { AKANTU_DEBUG_ERROR("The number of fragments is wrong! Numerical: " << nb_fragment_num << " Theoretical: " << frag); return EXIT_FAILURE; } /// check mass computation if (frag < total_nb_fragment) { Real total_mass = 0.; UInt small_fragments = 0; for (UInt f = 0; f < nb_fragment_num; ++f) { const Vector<Real> & current_inertia = inertia_moments_begin[f]; if (Math::are_float_equal(fragment_mass(f, 0), frag_theo_mass)) { /// check center of mass if (fragment_center(f, 0) > (L * frag / total_nb_fragment - L / 2)) { AKANTU_DEBUG_ERROR("Fragment center is wrong!"); return EXIT_FAILURE; } /// check moment of inertia if (!isInertiaEqual(current_inertia, small_frag_inertia)) { AKANTU_DEBUG_ERROR("Inertia moments are wrong"); return EXIT_FAILURE; } ++small_fragments; total_mass += frag_theo_mass; } else { /// check the moment of inertia for the biggest fragment Real big_frag_mass = frag_theo_mass * (total_nb_fragment - frag + 1); Real big_frag_size = el_size * (total_nb_fragment - frag + 1); Vector<Real> big_frag_inertia(spatial_dimension); big_frag_inertia(0) = big_frag_mass * (h*h + h*h) / 12.; big_frag_inertia(1) = big_frag_mass * (big_frag_size*big_frag_size + h*h) / 12.; big_frag_inertia(2) = big_frag_mass * (big_frag_size*big_frag_size + h*h) / 12.; std::sort(big_frag_inertia.storage(), big_frag_inertia.storage() + spatial_dimension, std::greater<Real>()); if (!isInertiaEqual(current_inertia, big_frag_inertia)) { AKANTU_DEBUG_ERROR("Inertia moments are wrong"); return EXIT_FAILURE; } } } if (small_fragments != nb_fragment_num - 1) { AKANTU_DEBUG_ERROR("The number of small fragments is wrong!"); return EXIT_FAILURE; } if (!Math::are_float_equal(total_mass, small_fragments * frag_theo_mass)) { AKANTU_DEBUG_ERROR("The mass of small fragments is wrong!"); return EXIT_FAILURE; } } /// displace fragments rotateArray(mesh.getNodes(), -rotation_angle); // rotateArray(displacement, -rotation_angle); displaceElements(model, lim, el_size * 2); rotateArray(mesh.getNodes(), rotation_angle); // rotateArray(displacement, rotation_angle); model.updateResidual(); lim += el_size; } model.dump(); model.dump("cohesive elements"); /// check centers const Array<Real> & fragment_velocity = fragment_manager.getVelocity(); Real initial_position = -L / 2. + el_size / 2.; for (UInt frag = 0; frag < total_nb_fragment; ++frag) { Real theoretical_center = initial_position + el_size * frag; UInt f_index = 0; while (f_index < total_nb_fragment && !Math::are_float_equal(fragment_center(f_index, 0), theoretical_center)) ++f_index; if (f_index == total_nb_fragment) { AKANTU_DEBUG_ERROR("The fragments' center is wrong!"); return EXIT_FAILURE; } f_index = 0; while (f_index < total_nb_fragment && !Math::are_float_equal(fragment_velocity(f_index, 0), theoretical_center)) ++f_index; if (f_index == total_nb_fragment) { AKANTU_DEBUG_ERROR("The fragments' velocity is wrong!"); return EXIT_FAILURE; } } finalize(); if (prank == 0) std::cout << "OK: test_cohesive_buildfragments was passed!" << std::endl; return EXIT_SUCCESS; } void verticalInsertionLimit(SolidMechanicsModelCohesive & model) { UInt spatial_dimension = model.getSpatialDimension(); const Mesh & mesh_facets = model.getMeshFacets(); const Array<Real> & position = mesh_facets.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for(; it != end; ++it) { ElementType type = *it; Array<bool> & check_facets = model.getElementInserter().getCheckFacets(type, ghost_type); const Array<UInt> & connectivity = mesh_facets.getConnectivity(type, ghost_type); UInt nb_nodes_per_facet = connectivity.getNbComponent(); for (UInt f = 0; f < check_facets.getSize(); ++f) { if (!check_facets(f)) continue; UInt nb_aligned_nodes = 1; Real first_node_pos = position(connectivity(f, 0), 0); for (; nb_aligned_nodes < nb_nodes_per_facet; ++nb_aligned_nodes) { Real other_node_pos = position(connectivity(f, nb_aligned_nodes), 0); if (! Math::are_float_equal(first_node_pos, other_node_pos)) break; } if (nb_aligned_nodes != nb_nodes_per_facet) { check_facets(f) = false; } } } } } void displaceElements(SolidMechanicsModelCohesive & model, const Real lim, const Real amount) { UInt spatial_dimension = model.getSpatialDimension(); Array<Real> & displacement = model.getDisplacement(); Mesh & mesh = model.getMesh(); UInt nb_nodes = mesh.getNbNodes(); Array<bool> displaced(nb_nodes); displaced.clear(); Vector<Real> barycenter(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { ElementType type = *it; const Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_element = connectivity.getSize(); UInt nb_nodes_per_element = connectivity.getNbComponent(); Array<UInt>::const_vector_iterator conn_el = connectivity.begin(nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, barycenter.storage(), ghost_type); if (barycenter(0) < lim) { const Vector<UInt> & conn = conn_el[el]; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = conn(n); if (!displaced(node)) { displacement(node, 0) -= amount; displaced(node) = true; } } } } } } } bool isInertiaEqual(const Vector<Real> & a, const Vector<Real> & b) { UInt nb_terms = a.size(); UInt equal_terms = 0; while (equal_terms < nb_terms && std::abs(a(equal_terms) - b(equal_terms)) / a(equal_terms) < Math::getTolerance()) ++equal_terms; return equal_terms == nb_terms; } void rotateArray(Array<Real> & array, Real angle) { UInt spatial_dimension = array.getNbComponent(); Real rotation_values[] = {std::cos(angle), std::sin(angle), 0, -std::sin(angle), std::cos(angle), 0, 0, 0, 1}; Matrix<Real> rotation(rotation_values, spatial_dimension, spatial_dimension); RVector displaced_node(spatial_dimension); Array<Real>::vector_iterator node_it = array.begin(spatial_dimension); Array<Real>::vector_iterator node_end = array.end(spatial_dimension); for (; node_it != node_end; ++node_it) { displaced_node.mul<false>(rotation, *node_it); *node_it = displaced_node; } } UInt getNbBigFragments(FragmentManager & fragment_manager, UInt minimum_nb_elements) { fragment_manager.computeNbElementsPerFragment(); const Array<UInt> & nb_elements_per_fragment = fragment_manager.getNbElementsPerFragment(); UInt nb_fragment = fragment_manager.getNbFragment(); UInt nb_big_fragment = 0; for (UInt frag = 0; frag < nb_fragment; ++frag) { if (nb_elements_per_fragment(frag) >= minimum_nb_elements) { ++nb_big_fragment; } } return nb_big_fragment; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc index f5b83daac..ece21b065 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc @@ -1,172 +1,172 @@ /** * @file test_cohesive_parallel_extrinsic.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief parallel test for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "dumper_paraview.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); const UInt max_steps = 500; UInt spatial_dimension = 2; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("mesh.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); // debug::setDebugLevel(dblDump); partition->partitionate(psize); // debug::setDebugLevel(dblWarning); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); // debug::setDebugLevel(dblDump); // std::cout << mesh << std::endl; // debug::setDebugLevel(dblWarning); model.initFull(SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); model.limitInsertion(_y, -0.30, -0.20); model.updateAutomaticInsertion(); // debug::setDebugLevel(dblDump); // std::cout << mesh_facets << std::endl; // debug::setDebugLevel(dblWarning); Real time_step = model.getStableTimeStep()*0.1; model.setTimeStep(time_step); std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array<Real> & position = mesh.getNodes(); Array<Real> & velocity = model.getVelocity(); Array<bool> & boundary = model.getBlockedDOFs(); Array<Real> & displacement = model.getDisplacement(); // const Array<Real> & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); /// boundary conditions for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) boundary(n, 1) = true; if (position(n, 0) > 0.99 || position(n, 0) < -0.99) boundary(n, 0) = true; } /// initial conditions Real loading_rate = 0.5; Real disp_update = loading_rate * time_step; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 1) = loading_rate * position(n, 1); } model.synchronizeBoundaries(); model.updateResidual(); model.setBaseName("extrinsic_parallel"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("grad_u"); model.addDumpField("partitions"); // model.getDumper().getDumper().setMode(iohelper::BASE64); model.dump(); model.setBaseNameToDumper("cohesive elements", "extrinsic_parallel_cohesive_elements"); model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.addDumpFieldToDumper("cohesive elements", "damage"); model.dump("cohesive elements"); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { /// update displacement on extreme nodes for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) displacement(n, 1) += disp_update * position(n, 1); } model.checkCohesiveStress(); model.solveStep(); // model.dump(); if(s % 10 == 0) { if(prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; } // // update displacement // for (UInt n = 0; n < nb_nodes; ++n) { // if (position(n, 1) + displacement(n, 1) > 0) { // displacement(n, 0) -= 0.01; // } // } // Real Ed = dynamic_cast<MaterialCohesive&> (model.getMaterial(1)).getDissipatedEnergy(); // Real Er = dynamic_cast<MaterialCohesive&> (model.getMaterial(1)).getReversibleEnergy(); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } model.dump(); model.dump("cohesive elements"); // edis.close(); // erev.close(); Real Ed = model.getEnergy("dissipated"); Real Edt = 200 * sqrt(2); if(prank == 0) { std::cout << Ed << " " << Edt << std::endl; if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; finalize(); return EXIT_FAILURE; } } finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron.cc index 05e10df9c..256c12b66 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron.cc @@ -1,230 +1,230 @@ /** * @file test_cohesive_parallel_extrinsic_tetrahedron.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief 3D extrinsic cohesive elements test * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "material_cohesive_linear.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; Real function(Real constant, Real x, Real y, Real z) { return constant + 2. * x + 3. * y + 4 * z; } int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); debug::setDebugLevel(dblWarning); // const UInt max_steps = 1000; // Real increment = 0.005; const UInt spatial_dimension = 3; Math::setTolerance(1.e-12); ElementType type = _tetrahedron_10; ElementType type_facet = Mesh::getFacetType(type); ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("tetrahedron.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } SolidMechanicsModelCohesive model(mesh); /// model initialization model.initParallel(partition, NULL, true); model.initFull(SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); const MaterialCohesiveLinear<3> & mat_cohesive = dynamic_cast < const MaterialCohesiveLinear<3> & > (model.getMaterial(1)); const Real sigma_c = mat_cohesive.getParam< RandomInternalField<Real, FacetInternalField> >("sigma_c"); const Real beta = mat_cohesive.getParam<Real>("beta"); // const Real G_cI = mat_cohesive.getParam<Real>("G_cI"); Array<Real> & position = mesh.getNodes(); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ /// compute quadrature points positions on facets const Mesh & mesh_facets = model.getMeshFacets(); UInt nb_facet = mesh_facets.getNbElement(type_facet); UInt nb_quad_per_facet = model.getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); UInt nb_tot_quad = nb_quad_per_facet * nb_facet; Array<Real> quad_facets(nb_tot_quad, spatial_dimension); model.getFEEngine("FacetsFEEngine").interpolateOnIntegrationPoints(position, quad_facets, spatial_dimension, type_facet); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ /// compute quadrature points position of the elements UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); UInt nb_element = mesh.getNbElement(type); UInt nb_tot_quad_el = nb_quad_per_element * nb_element; Array<Real> quad_elements(nb_tot_quad_el, spatial_dimension); model.getFEEngine().interpolateOnIntegrationPoints(position, quad_elements, spatial_dimension, type); /// assign some values to stresses Array<Real> & stress = const_cast<Array<Real>&>(model.getMaterial(0).getStress(type)); Array<Real>::iterator<Matrix<Real> > stress_it = stress.begin(spatial_dimension, spatial_dimension); for (UInt q = 0; q < nb_tot_quad_el; ++q, ++stress_it) { /// compute values for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = i; j < spatial_dimension; ++j) { UInt index = i * spatial_dimension + j; (*stress_it)(i, j) = index * function(sigma_c * 5, quad_elements(q, 0), quad_elements(q, 1), quad_elements(q, 2)); } } /// fill symmetrical part for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < i; ++j) { (*stress_it)(i, j) = (*stress_it)(j, i); } } } /// compute stress on facet quads Array<Real> stress_facets(nb_tot_quad, spatial_dimension * spatial_dimension); Array<Real>::iterator<Matrix<Real> > stress_facets_it = stress_facets.begin(spatial_dimension, spatial_dimension); for (UInt q = 0; q < nb_tot_quad; ++q, ++stress_facets_it) { /// compute values for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = i; j < spatial_dimension; ++j) { UInt index = i * spatial_dimension + j; (*stress_facets_it)(i, j) = index * function(sigma_c * 5, quad_facets(q, 0), quad_facets(q, 1), quad_facets(q, 2)); } } /// fill symmetrical part for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < i; ++j) { (*stress_facets_it)(i, j) = (*stress_facets_it)(j, i); } } } /// insert cohesive elements model.checkCohesiveStress(); /// check insertion stress const Array<Real> & normals = model.getFEEngine("FacetsFEEngine").getNormalsOnIntegrationPoints(type_facet); const Array<Real> & tangents = model.getTangents(type_facet); const Array<Real> & sigma_c_eff = mat_cohesive.getInsertionTraction(type_cohesive); Vector<Real> normal_stress(spatial_dimension); const Array<std::vector<Element> > & coh_element_to_facet = mesh_facets.getElementToSubelement(type_facet); Array<Real>::iterator<Matrix<Real> > quad_facet_stress = stress_facets.begin(spatial_dimension, spatial_dimension); Array<Real>::const_iterator<Vector<Real> > quad_normal = normals.begin(spatial_dimension); Array<Real>::const_iterator<Vector<Real> > quad_tangents = tangents.begin(tangents.getNbComponent()); for (UInt f = 0; f < nb_facet; ++f) { const Element & cohesive_element = coh_element_to_facet(f)[1]; for (UInt q = 0; q < nb_quad_per_facet; ++q, ++quad_facet_stress, ++quad_normal, ++quad_tangents) { if (cohesive_element == ElementNull) continue; normal_stress.mul<false>(*quad_facet_stress, *quad_normal); Real normal_contrib = normal_stress.dot(*quad_normal); Real first_tangent_contrib = 0; for (UInt dim = 0; dim < spatial_dimension; ++dim) first_tangent_contrib += normal_stress(dim) * (*quad_tangents)(dim); Real second_tangent_contrib = 0; for (UInt dim = 0; dim < spatial_dimension; ++dim) second_tangent_contrib += normal_stress(dim) * (*quad_tangents)(dim + spatial_dimension); Real tangent_contrib = std::sqrt(first_tangent_contrib * first_tangent_contrib + second_tangent_contrib * second_tangent_contrib); normal_contrib = std::max(0., normal_contrib); Real effective_norm = std::sqrt(normal_contrib * normal_contrib + tangent_contrib * tangent_contrib / beta / beta); if (effective_norm < sigma_c) continue; if (!Math::are_float_equal(effective_norm, sigma_c_eff(cohesive_element.element * nb_quad_per_facet + q))) { std::cout << "Insertion tractions do not match" << std::endl; finalize(); return EXIT_FAILURE; } } } finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc index 2abbd0b12..70404b8ef 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc @@ -1,395 +1,395 @@ /** * @file test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Displacement test for 3D cohesive elements * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "dumper_paraview.hh" #include "material_cohesive_linear.hh" #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ using namespace akantu; bool checkDisplacement(SolidMechanicsModelCohesive & model, ElementType type, std::ofstream & error_output, UInt step, bool barycenters); int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); debug::setDebugLevel(dblWarning); const UInt max_steps = 500; Math::setTolerance(1.e-12); UInt spatial_dimension = 3; ElementType type = _tetrahedron_10; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("tetrahedron.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); // debug::setDebugLevel(dblDump); partition->partitionate(psize); // debug::setDebugLevel(dblWarning); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); // debug::setDebugLevel(dblDump); // std::cout << mesh << std::endl; // debug::setDebugLevel(dblWarning); model.initFull(SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ // Array<Real> limits(spatial_dimension, 2); // limits(0, 0) = -0.01; // limits(0, 1) = 0.01; // limits(1, 0) = -100; // limits(1, 1) = 100; // limits(2, 0) = -100; // limits(2, 1) = 100; // model.enableFacetsCheckOnArea(limits); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ // debug::setDebugLevel(dblDump); // std::cout << mesh_facets << std::endl; // debug::setDebugLevel(dblWarning); Real time_step = model.getStableTimeStep()*0.1; model.setTimeStep(time_step); std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array<Real> & position = mesh.getNodes(); Array<Real> & velocity = model.getVelocity(); Array<bool> & boundary = model.getBlockedDOFs(); Array<Real> & displacement = model.getDisplacement(); // const Array<Real> & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); /// boundary conditions for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 0) > 0.99 || position(n, 0) < -0.99) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { boundary(n, dim) = true; } } if (position(n, 0) > 0.99 || position(n, 0) < -0.99) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { boundary(n, dim) = true; } } } // #if defined (AKANTU_DEBUG_TOOLS) // Vector<Real> facet_center(spatial_dimension); // facet_center(0) = 0; // facet_center(1) = -0.16666667; // facet_center(2) = 0.5; // debug::element_manager.setMesh(mesh); // debug::element_manager.addModule(debug::_dm_material_cohesive); // debug::element_manager.addModule(debug::_dm_debug_tools); // //debug::element_manager.addModule(debug::_dm_integrator); // #endif /// initial conditions Real loading_rate = 1; Real disp_update = loading_rate * time_step; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 0) = loading_rate * position(n, 0); velocity(n, 1) = loading_rate * position(n, 0); } model.synchronizeBoundaries(); model.updateResidual(); std::stringstream paraview_output; paraview_output << "extrinsic_parallel_tetrahedron_" << psize; model.setBaseName(paraview_output.str()); model.addDumpFieldVector("displacement"); model.addDumpFieldVector("velocity" ); model.addDumpFieldVector("acceleration"); model.addDumpFieldVector("residual" ); model.addDumpFieldTensor("stress"); model.addDumpFieldTensor("grad_u"); model.addDumpField("partitions"); // model.getDumper().getDumper().setMode(iohelper::BASE64); model.dump(); model.setBaseNameToDumper("cohesive elements", paraview_output.str()+"_cohesive_elements"); model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.addDumpFieldToDumper("cohesive elements", "damage"); model.dump("cohesive elements"); std::stringstream error_stream; error_stream << "error" << ".csv"; std::ofstream error_output; error_output.open(error_stream.str().c_str()); error_output << "# Step, Average, Max, Min" << std::endl; if (checkDisplacement(model, type, error_output, 0, true)) {} /// Main loop for (UInt s = 1; s <= max_steps; ++s) { /// update displacement on extreme nodes for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (position(n, 0) > 0.99 || position(n, 0) < -0.99) { displacement(n, 0) += disp_update * position(n, 0); displacement(n, 1) += disp_update * position(n, 0); } } model.checkCohesiveStress(); model.solveStep(); if(s % 100 == 0) { if(prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; } } model.dump(); model.dump("cohesive elements"); if (!checkDisplacement(model, type, error_output, max_steps, false)) { finalize(); return EXIT_FAILURE; } finalize(); return EXIT_SUCCESS; } bool checkDisplacement(SolidMechanicsModelCohesive & model, ElementType type, std::ofstream & error_output, UInt step, bool barycenters) { Mesh & mesh = model.getMesh(); UInt spatial_dimension = mesh.getSpatialDimension(); const Array<UInt> & connectivity = mesh.getConnectivity(type); const Array<Real> & displacement = model.getDisplacement(); UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_elem = Mesh::getNbNodesPerElement(type); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); if (psize == 1) { std::stringstream displacement_file; displacement_file << "displacement/displacement_" << std::setfill('0') << std::setw(6) << step; std::ofstream displacement_output; displacement_output.open(displacement_file.str().c_str()); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = connectivity(el, n); for (UInt dim = 0; dim < spatial_dimension; ++dim) { displacement_output << std::setprecision(15) << displacement(node, dim) << " "; } displacement_output << std::endl; } } displacement_output.close(); if (barycenters) { std::stringstream barycenter_file; barycenter_file << "displacement/barycenters"; std::ofstream barycenter_output; barycenter_output.open(barycenter_file.str().c_str()); Element element(type, 0); Vector<Real> bary(spatial_dimension); for (UInt el = 0; el < nb_element; ++el) { element.element = el; mesh.getBarycenter(element, bary); for (UInt dim = 0; dim < spatial_dimension; ++dim) { barycenter_output << std::setprecision(15) << bary(dim) << " "; } barycenter_output << std::endl; } barycenter_output.close(); } } else { if (barycenters) return true; /// read data std::stringstream displacement_file; displacement_file << "displacement/displacement_" << std::setfill('0') << std::setw(6) << step; std::ifstream displacement_input; displacement_input.open(displacement_file.str().c_str()); Array<Real> displacement_serial(0, spatial_dimension); Vector<Real> disp_tmp(spatial_dimension); while (displacement_input.good()) { for (UInt i = 0; i < spatial_dimension; ++i) displacement_input >> disp_tmp(i); displacement_serial.push_back(disp_tmp); } std::stringstream barycenter_file; barycenter_file << "displacement/barycenters"; std::ifstream barycenter_input; barycenter_input.open(barycenter_file.str().c_str()); Array<Real> barycenter_serial(0, spatial_dimension); while (barycenter_input.good()) { for (UInt dim = 0; dim < spatial_dimension; ++dim) barycenter_input >> disp_tmp(dim); barycenter_serial.push_back(disp_tmp); } Element element(type, 0); Vector<Real> bary(spatial_dimension); Array<Real>::iterator<Vector<Real> > it; Array<Real>::iterator<Vector<Real> > begin = barycenter_serial.begin(spatial_dimension); Array<Real>::iterator<Vector<Real> > end = barycenter_serial.end(spatial_dimension); Array<Real>::const_iterator<Vector<Real> > disp_it; Array<Real>::iterator<Vector<Real> > disp_serial_it; Vector<Real> difference(spatial_dimension); Array<Real> error; /// compute error for (UInt el = 0; el < nb_element; ++el) { element.element = el; mesh.getBarycenter(element, bary); /// find element for (it = begin; it != end; ++it) { UInt matched_dim = 0; while (matched_dim < spatial_dimension && Math::are_float_equal(bary(matched_dim), (*it)(matched_dim))) ++matched_dim; if (matched_dim == spatial_dimension) break; } if (it == end) { std::cout << "Element barycenter not found!" << std::endl; return false; } UInt matched_el = it - begin; disp_serial_it = displacement_serial.begin(spatial_dimension) + matched_el * nb_nodes_per_elem; for (UInt n = 0; n < nb_nodes_per_elem; ++n, ++disp_serial_it) { UInt node = connectivity(el, n); if (!mesh.isLocalOrMasterNode(node)) continue; disp_it = displacement.begin(spatial_dimension) + node; difference = *disp_it; difference -= *disp_serial_it; error.push_back(difference.norm()); } } /// compute average error Real average_error = std::accumulate(error.begin(), error.end(), 0.); comm.allReduce(&average_error, 1, _so_sum); UInt error_size = error.getSize(); comm.allReduce(&error_size, 1, _so_sum); average_error /= error_size; /// compute maximum and minimum Real max_error = *std::max_element(error.begin(), error.end()); comm.allReduce(&max_error, 1, _so_max); Real min_error = *std::min_element(error.begin(), error.end()); comm.allReduce(&min_error, 1, _so_min); /// output data if (prank == 0) { error_output << step << ", " << average_error << ", " << max_error << ", " << min_error << std::endl; } if (max_error > 1.e-9) { std::cout << "Displacement error is too big!" << std::endl; return false; } } return true; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic_IG_TG/test_cohesive_parallel_extrinsic_IG_TG.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic_IG_TG/test_cohesive_parallel_extrinsic_IG_TG.cc index 84d56d478..e5aba2874 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic_IG_TG/test_cohesive_parallel_extrinsic_IG_TG.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic_IG_TG/test_cohesive_parallel_extrinsic_IG_TG.cc @@ -1,295 +1,295 @@ /** * @file test_cohesive_parallel_extrinsic_IG_TG.cc * * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Test for considering different cohesive properties for * intergranular (IG) and transgranular (TG) fractures in extrinsic * cohesive elements * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include <limits> #include <fstream> #include <iostream> /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "material_cohesive_linear.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; class MultiGrainMaterialSelector : public DefaultMaterialCohesiveSelector { public: MultiGrainMaterialSelector(const SolidMechanicsModelCohesive & model, const ID & transgranular_id, const ID & intergranular_id) : DefaultMaterialCohesiveSelector(model), transgranular_id(transgranular_id), intergranular_id(intergranular_id), model(model), mesh(model.getMesh()), mesh_facets(model.getMeshFacets()), spatial_dimension(model.getSpatialDimension()), nb_IG(0), nb_TG(0) { } UInt 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); const Element & el1 = element_to_subelement[0]; const Element & el2 = element_to_subelement[1]; UInt grain_id1 = mesh.getData<UInt>("tag_0", el1.type, el1.ghost_type)(el1.element); if(el2 != ElementNull) { UInt grain_id2 = mesh.getData<UInt>("tag_0", el2.type, el2.ghost_type)(el2.element); if (grain_id1 == grain_id2){ //transgranular = 0 indicator nb_TG++; return model.getMaterialIndex(transgranular_id); } else { //intergranular = 1 indicator nb_IG++; return model.getMaterialIndex(intergranular_id); } } else { //transgranular = 0 indicator nb_TG++; return model.getMaterialIndex(transgranular_id); } } else { return DefaultMaterialCohesiveSelector::operator()(element); } } private: ID transgranular_id, intergranular_id; const SolidMechanicsModelCohesive & model; const Mesh & mesh; const Mesh & mesh_facets; UInt spatial_dimension; UInt nb_IG; UInt nb_TG; }; /* -------------------------------------------------------------------------- */ void limitInsertion(SolidMechanicsModelCohesive & model) { Real tolerance = 0.1; const Mesh & mesh = model.getMesh(); const Mesh & mesh_facets = model.getMeshFacets(); CohesiveElementInserter & inserter = model.getElementInserter(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector<Real> bary_facet(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for(; it != end; ++it) { ElementType type = *it; Array<bool> & f_check = inserter.getCheckFacets(type, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (f_check(f)) { mesh_facets.getBarycenter(f, type, bary_facet.storage(), ghost_type); if ( !(bary_facet(0) > -tolerance && bary_facet(0) < tolerance) && !(bary_facet(1) > -tolerance && bary_facet(1) < tolerance) ) f_check(f) = false; } } } } model.updateAutomaticInsertion(); } int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); debug::setDebugLevel(dblWarning); const UInt spatial_dimension = 2; const UInt max_steps = 600; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { mesh.read("square.msh"); partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } SolidMechanicsModelCohesive model(mesh); /// model initialization model.initParallel(partition, NULL, true); delete partition; MultiGrainMaterialSelector material_selector(model, "TG_cohesive", "IG_cohesive"); model.setMaterialSelector(material_selector); model.initFull(SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true, false)); Real time_step = model.getStableTimeStep()*0.1; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; limitInsertion(model); // std::cout << mesh << std::endl; Array<Real> & position = mesh.getNodes(); Array<Real> & velocity = model.getVelocity(); Array<bool> & boundary = model.getBlockedDOFs(); Array<Real> & displacement = model.getDisplacement(); // const Array<Real> & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); /// boundary conditions for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99|| position(n, 1) < -0.99) boundary(n, 1) = true; if (position(n, 0) > 0.99 || position(n, 0) < -0.99) boundary(n, 0) = true; } model.synchronizeBoundaries(); model.updateResidual(); model.setBaseName("extrinsic"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("strain"); model.addDumpField("partitions"); model.setBaseNameToDumper("cohesive elements", "extrinsic_cohesive"); model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.addDumpFieldToDumper("cohesive elements", "damage"); model.dump(); model.dump("cohesive elements"); /// initial conditions Real loading_rate = 0.1; // bar_height = 2 Real VI = loading_rate * 2* 0.5; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 1) = loading_rate * position(n, 1); velocity(n, 0) = loading_rate * position(n, 0); } // std::ofstream edis("edis.txt"); // std::ofstream erev("erev.txt"); // Array<Real> & residual = model.getResidual(); // model.dump(); // const Array<Real> & stress = model.getMaterial(0).getStress(type); Real dispy = 0; // UInt nb_coh_elem = 0; /// Main loop for (UInt s = 1; s <= max_steps; ++s) { dispy += VI * time_step; /// update displacement on extreme nodes for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (position(n, 1) > 0.99){ displacement(n, 1) = dispy; velocity(n,1) = VI;} if (position(n, 1) < -0.99){ displacement(n, 1) = -dispy; velocity(n,1) = -VI;} if (position(n, 0) > 0.99){ displacement(n, 0) = dispy; velocity(n,0) = VI;} if (position(n, 0) < -0.99){ displacement(n, 0) = -dispy; velocity(n,0) = -VI;} } model.checkCohesiveStress(); model.solveStep(); if(s % 10 == 0) { if(prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; // model.dump(); // model.dump("cohesive elements"); } // Real Ed = model.getEnergy("dissipated"); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } model.dump(); model.dump("cohesive elements"); // edis.close(); // erev.close(); // mesh.write("mesh_final.msh"); Real Ed = model.getEnergy("dissipated"); Real Edt = 40; if(prank == 0) std::cout << Ed << " " << Edt << std::endl; if (Ed < Edt * 0.99 || Ed > Edt * 1.01 || std::isnan(Ed)) { if(prank == 0) std::cout << "The dissipated energy is incorrect" << std::endl; finalize(); return EXIT_FAILURE; } // for (UInt n = 0; n < position.getSize(); ++n) { // for (UInt s = 0; s < spatial_dimension; ++s) { // position(n, s) += displacement(n, s); // } // } finalize(); if(prank == 0) std::cout << "OK: test_cohesive_extrinsic_IG_TG was passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_insertion_along_physical_surfaces.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_insertion_along_physical_surfaces.cc index 74d52adbf..b37321c1b 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_insertion_along_physical_surfaces.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_insertion_along_physical_surfaces.cc @@ -1,118 +1,118 @@ /** * @file test_cohesive_insertion_along_physical_surfaces.cc * @author Fabian Barras <fabian.barras@epfl.ch> * @date Fri Aug 7 09:07:44 2015 * * @brief Test parallel intrinsic insertion of cohesive elements along physical surfaces * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <limits> #include <fstream> #include <iostream> /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize("input_file.dat", argc, argv); Math::setTolerance(1e-15); const UInt spatial_dimension = 3; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank==0){ mesh.read("3d_spherical_inclusion.msh"); partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition); mesh.createGroupsFromMeshData<std::string>("physical_names"); model.initFull(SolidMechanicsModelCohesiveOptions(_static)); std::vector<std::string> surfaces_name = {"interface", "coh1", "coh2", "coh3", "coh4", "coh5"}; UInt nb_surf = surfaces_name.size(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { std::string ghost_str; if(*gt == 1) ghost_str = "ghost"; else ghost_str = "not ghost"; Mesh::type_iterator it = mesh.firstType(spatial_dimension, *gt, _ek_cohesive); Mesh::type_iterator end = mesh.lastType(spatial_dimension, *gt, _ek_cohesive); for(; it != end; ++it) { Array<UInt> & material_id = mesh.getMeshFacets().getData<UInt>("physical_names")(mesh.getFacetType(*it), *gt); for (UInt i = 0; i < nb_surf; ++i) { UInt expected_insertion = 0; for(UInt m = 0; m<material_id.getSize();++m) { if(material_id(m)==model.SolidMechanicsModel::getMaterialIndex(surfaces_name[i])) ++expected_insertion; } UInt inserted_elements; inserted_elements = model.getMaterial(surfaces_name[i]).getElementFilter()(*it,*gt).getSize(); if (expected_insertion != inserted_elements) { std::cerr << std::endl << "!!! Mismatch in insertion of surface named " << surfaces_name[i] << " in proc n° " << prank << " --> " << inserted_elements << " inserted elements of type " << ghost_str << " out of " << expected_insertion << std::endl; return EXIT_FAILURE; } } } } model.assembleStiffnessMatrix(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_intrinsic_implicit_insertion.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_intrinsic_implicit_insertion.cc index d6643a5a1..ad60ef2ef 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_intrinsic_implicit_insertion.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_insertion/test_cohesive_parallel_intrinsic_implicit_insertion.cc @@ -1,270 +1,270 @@ /** * @file test_cohesive_parallel_intrinsic_implicit_insertion.cc * @author Fabian Barras <fabian.barras@epfl.ch> * @date Fri Aug 5 17:05:59 2016 * * @brief Verifying the proper insertion and synchronization of intrinsic cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <limits> #include <fstream> #include <iostream> /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; std::ofstream output; /* -------------------------------------------------------------------------- */ void printMeshContent(Mesh & mesh) { - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); comm.barrier(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(_all_dimensions, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(_all_dimensions, *gt, _ek_not_defined); for(; first != last; ++first) { UInt nb_element = mesh.getNbElement(*first,*gt); output << std::endl << "Element type: " << *first << ", " << *gt << ": " << nb_element << " in the mesh of processor " << prank << std::endl; Array<UInt> & conn = mesh.getConnectivity(*first,*gt); for (UInt i = 0; i < conn.getSize(); ++i) { output << "Element no " << i << " "; for (UInt j = 0; j < conn.getNbComponent(); ++j) { output << conn(i,j) << " "; } output << std::endl; } } } } /* -------------------------------------------------------------------------- */ void printNodeList(Mesh & mesh) { Array<double> & nodes = mesh.getNodes(); output << "Number of nodes: " << mesh.getNbNodes()<< std::endl; for (UInt i = 0; i < mesh.getNbNodes(); ++i) { output<<"Node # " << i << ", x-coord: " << nodes(i,0) << ", y-coord: " << nodes(i,1) << ", of type: " << mesh.getNodeType(i) << std::endl; } output << std::endl; } /* -------------------------------------------------------------------------- */ void getGlobalIDs(Mesh & mesh) { const Array<UInt> & glob_id = mesh.getGlobalNodesIds(); if(&glob_id) { output << "Global nodes ID: " << std::endl; for (UInt i = 0; i < glob_id.getSize(); ++i) { output << i << " " << glob_id(i) << std::endl; } } output << std::endl; } /* -------------------------------------------------------------------------- */ void printSynchroinfo(Mesh & mesh, const DistributedSynchronizer & synch) { - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); Int psize = comm.getNbProc(); if(comm.getNbProc()==1) return; for (Int p = 0; p < psize; ++p) { if (p==prank) continue; output << "From processor " << prank << " to processor " << p << std::endl; const Array<Element> & sele = *(synch.getSendElement()+p); output << " Sending element(s): " << std::endl; for (UInt i = 0; i < sele.getSize(); ++i) { output << sele(i) << std::endl; } const Array<Element> & rele = *(synch.getReceiveElement()+p); output <<" Receiving element(s): " << std::endl; for (UInt i = 0; i < rele.getSize(); ++i) { output << rele(i) << std::endl; } } output << std::endl; } /* -------------------------------------------------------------------------- */ void printDOF(SolidMechanicsModelCohesive & model) { - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); if(comm.getNbProc()==1) return; Int prank = comm.whoAmI(); const DOFSynchronizer & dof = model.getDOFSynchronizer(); output << "Number of global dofs " << dof.getNbGlobalDOFs() << " for processor "<< prank << std::endl; const Array<UInt> & dof_global_ids = dof.getDOFGlobalIDs(); for (UInt i = 0; i < dof_global_ids.getSize(); ++i) { output << "Local dof " << i << ", global id: " << dof_global_ids(i) << std::endl; } output << std::endl; } /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { std::string input_file = "input_file_iii.dat"; std::string mesh_file = "2d_basic_interface.msh"; std::string dir = "output_dir/"; initialize(input_file, argc, argv); debug::setDebugLevel(dbl0); const UInt spatial_dimension = 2; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; std::stringstream filename; filename << dir.c_str() << "output_from_proc_" << prank << "_out_of_" << psize << ".out"; output.open(filename.str()); if(prank==0){ mesh.read(mesh_file); partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); const ElementTypeMapArray<UInt> & partitions = partition->getPartitions(); output << "The root processor read the mesh." << std::endl << "Only GMSH physical objects are created in the mesh." <<std::endl; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(_all_dimensions, *gt); Mesh::type_iterator last = mesh.lastType(_all_dimensions, *gt); for(; first != last; ++first) { output << "Element type: " << *first << " ghost type: " << *gt << std::endl; UInt nb_element = mesh.getNbElement(*first,*gt); output << nb_element << " to partitionate between " << psize << " processsors" << std::endl; Array<UInt> part = partitions(*first, *gt); for (UInt i = 0; i < part.getSize(); ++i) { output << i << " " << part(i) << std::endl; } } } output << "Nodes are also read and set with type -1 (normal node)" << std::endl; printNodeList(mesh); } SolidMechanicsModelCohesive model(mesh); output << "Before initParallel(), non-root processors have empty Mesh object" << std::endl; printMeshContent(mesh); model.initParallel(partition); output << "After initParallel(), Mesh object on each processor is a local partionated mesh containing ghost elements" << std::endl; printMeshContent(mesh); output << "Nodes are also partionated and new node types are defined:" << std::endl; printNodeList(mesh); output << "-3: pure ghost node -> not a local node" << std::endl << "-2: master node -> node shared with other processor(s) -> local and global node" <<std::endl << ">0: slave node -> -> node shared with other processor(s) -> only local node (its id is the rank of the processor owning the master node)" <<std::endl; output << "Each local node has a corresponding global id used during assembly: " <<std::endl; getGlobalIDs(mesh); Mesh & mesh_facets = mesh.getMeshFacets(); output << "Within cohesive element model, initParallel() creates a second Mesh object usually called mesh_facet" << std::endl << "This Mesh object contains all sub-dimensional elements where potential cohesive element can be inserted" << std::endl; printMeshContent(mesh_facets); const DistributedSynchronizer & synch_model = model.getSynchronizer(); output << "The distributed synchronizer of solid mechanics model is used to synchronize fields with ghost element:" << std::endl; printSynchroinfo(mesh, synch_model); mesh.createGroupsFromMeshData<std::string>("physical_names"); model.initFull(SolidMechanicsModelCohesiveOptions(_static)); output << "In case of insertion along physical objects, cohesive elements are created during initFull()" << std::endl; output << "Elements list after insertion" << std::endl; printMeshContent(mesh); output << "Node list after insertion: (Total number of nodes " << mesh.getNbNodes()<< ")"<< std::endl; printNodeList(mesh); output << "Node global ids after insertion: (Total number of nodes " << mesh.getNbGlobalNodes()<< ")"<< std::endl; getGlobalIDs(mesh); const DistributedSynchronizer & coh_synch_model = *(model.getCohesiveSynchronizer()); output << "Solid mechanics model cohesive has its own distributed synchronizer to handle ghost cohesive element:" << std::endl; printSynchroinfo(mesh, coh_synch_model); output << "A synchronizer dedicated to degrees of freedom (DOFs) is used by the solver to build matrices in parallel:" << std::endl << "This DOFSynchronizer is built based on nodes global id " << std::endl; printDOF(model); output.close(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc index 9bd19c8b7..f4d854bf0 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc @@ -1,160 +1,160 @@ /** * @file test_cohesive_parallel_intrinsic.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief parallel test for intrinsic cohesive elements * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); const UInt max_steps = 350; UInt spatial_dimension = 2; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("mesh.msh"); // /// insert cohesive elements // CohesiveElementInserter inserter(mesh); // inserter.setLimit('x', -0.26, -0.24); // inserter.insertIntrinsicElements(); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); // debug::setDebugLevel(dblDump); partition->partitionate(psize); // debug::setDebugLevel(dblWarning); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition); model.initFull(); model.limitInsertion(_x, -0.26, -0.24); model.insertIntrinsicElements(); debug::setDebugLevel(dblDump); std::cout << mesh << std::endl; debug::setDebugLevel(dblWarning); Real time_step = model.getStableTimeStep()*0.8; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array<Real> & position = mesh.getNodes(); Array<Real> & velocity = model.getVelocity(); Array<bool> & boundary = model.getBlockedDOFs(); // Array<Real> & displacement = model.getDisplacement(); // const Array<Real> & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); Real epsilon = std::numeric_limits<Real>::epsilon(); for (UInt n = 0; n < nb_nodes; ++n) { if (std::abs(position(n, 0) - 1.) < epsilon) boundary(n, 0) = true; } model.synchronizeBoundaries(); model.updateResidual(); model.setBaseName("intrinsic_parallel"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("strain"); model.addDumpField("partitions"); model.addDumpField("force"); model.dump(); model.setBaseNameToDumper("cohesive elements", "cohesive_elements_parallel_intrinsic"); model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.dump("cohesive elements"); /// initial conditions Real loading_rate = .2; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 0) = loading_rate * position(n, 0); } /// Main loop for (UInt s = 1; s <= max_steps; ++s) { model.solveStep(); if(s % 20 == 0) { model.dump(); model.dump("cohesive elements"); if(prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; } // // update displacement // for (UInt n = 0; n < nb_nodes; ++n) { // if (position(n, 1) + displacement(n, 1) > 0) { // displacement(n, 0) -= 0.01; // } // } // Real Ed = dynamic_cast<MaterialCohesive&> (model.getMaterial(1)).getDissipatedEnergy(); // Real Er = dynamic_cast<MaterialCohesive&> (model.getMaterial(1)).getReversibleEnergy(); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } // edis.close(); // erev.close(); Real Ed = model.getEnergy("dissipated"); Real Edt = 2 * sqrt(2); if(prank == 0) { std::cout << Ed << " " << Edt << std::endl; if (std::abs((Ed - Edt) / Edt) > 0.01 || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; return EXIT_FAILURE; } } finalize(); if(prank == 0) std::cout << "OK: Test passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc index f6607255d..983104b34 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc @@ -1,704 +1,704 @@ /** * @file test_cohesive_parallel_intrinsic_tetrahedron.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Test for 3D intrinsic cohesive elements simulation in parallel * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "dumper_paraview.hh" #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; void updateDisplacement(SolidMechanicsModelCohesive & model, const ElementTypeMapArray<UInt> & elements, Vector<Real> & increment); bool checkTractions(SolidMechanicsModelCohesive & model, Vector<Real> & opening, Vector<Real> & theoretical_traction, Matrix<Real> & rotation); void findNodesToCheck(const Mesh & mesh, const ElementTypeMapArray<UInt> & elements, Array<UInt> & nodes_to_check, Int psize); bool checkEquilibrium(const Mesh & mesh, const Array<Real> & residual); bool checkResidual(const Array<Real> & residual, const Vector<Real> & traction, const Array<UInt> & nodes_to_check, const Matrix<Real> & rotation); void findElementsToDisplace(const Mesh & mesh, ElementTypeMapArray<UInt> & elements); int main(int argc, char *argv[]) { initialize("material_tetrahedron.dat", argc, argv); const UInt spatial_dimension = 3; const UInt max_steps = 60; const Real increment_constant = 0.01; ElementType type = _tetrahedron_10; Math::setTolerance(1.e-10); Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); UInt nb_nodes_to_check_serial = 0; UInt total_nb_nodes = 0; UInt nb_elements_check_serial = 0; akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("tetrahedron.msh"); /// count nodes with zero position const Array<Real> & position = mesh.getNodes(); for (UInt n = 0; n < position.getSize(); ++n) { if (std::abs(position(n, 0) - 0.) < 1e-6) ++nb_nodes_to_check_serial; } // /// insert cohesive elements // CohesiveElementInserter inserter(mesh); // inserter.setLimit(0, -0.01, 0.01); // inserter.insertIntrinsicElements(); /// find nodes to check in serial ElementTypeMapArray<UInt> elements_serial("elements_serial", ""); findElementsToDisplace(mesh, elements_serial); nb_elements_check_serial = elements_serial(type).getSize(); total_nb_nodes = mesh.getNbNodes() + nb_nodes_to_check_serial; /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); debug::setDebugLevel(dblDump); partition->partitionate(psize); debug::setDebugLevel(dblInfo); } comm.broadcast(&nb_nodes_to_check_serial, 1, 0); comm.broadcast(&nb_elements_check_serial, 1, 0); SolidMechanicsModelCohesive model(mesh); model.initParallel(partition); model.initFull(); model.limitInsertion(_x, -0.01, 0.01); model.insertIntrinsicElements(); { comm.broadcast(&total_nb_nodes, 1, 0); Array<Int> nb_local_nodes(psize); nb_local_nodes.clear(); for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) ++nb_local_nodes(prank); } comm.allGather(nb_local_nodes.storage(), 1); UInt total_nb_nodes_parallel = std::accumulate(nb_local_nodes.begin(), nb_local_nodes.end(), 0); Array<UInt> global_nodes_list(total_nb_nodes_parallel); UInt first_global_node = std::accumulate(nb_local_nodes.begin(), nb_local_nodes.begin() + prank, 0); for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) { global_nodes_list(first_global_node) = mesh.getNodeGlobalId(n); ++first_global_node; } } comm.allGatherV(global_nodes_list.storage(), nb_local_nodes.storage()); if (prank == 0) std::cout << "Maximum node index: " << *(std::max_element(global_nodes_list.begin(), global_nodes_list.end())) << std::endl; Array<UInt> repeated_nodes; repeated_nodes.resize(0); for (UInt n = 0; n < total_nb_nodes_parallel; ++n) { UInt appearances = std::count(global_nodes_list.begin() + n, global_nodes_list.end(), global_nodes_list(n)); if (appearances > 1) { std::cout << "Node " << global_nodes_list(n) << " appears " << appearances << " times" << std::endl; std::cout << " in position: " << n; repeated_nodes.push_back(global_nodes_list(n)); UInt * node_position = global_nodes_list.storage() + n; for (UInt i = 1; i < appearances; ++i) { node_position = std::find(node_position + 1, global_nodes_list.storage() + total_nb_nodes_parallel, global_nodes_list(n)); UInt current_index = node_position - global_nodes_list.storage(); std::cout << ", " << current_index; } std::cout << std::endl << std::endl; } } for (UInt n = 0; n < mesh.getNbNodes(); ++n) { UInt global_node = mesh.getNodeGlobalId(n); if (std::find(repeated_nodes.begin(), repeated_nodes.end(), global_node) != repeated_nodes.end()) { std::cout << "Repeated global node " << global_node << " corresponds to local node " << n << std::endl; } } if (total_nb_nodes != total_nb_nodes_parallel) { if (prank == 0) { std::cout << "Error: total number of nodes is wrong in parallel" << std::endl; std::cout << "Serial: " << total_nb_nodes << " Parallel: " << total_nb_nodes_parallel << std::endl; } finalize(); return EXIT_FAILURE; } } model.updateResidual(); model.setBaseName("intrinsic_parallel_tetrahedron"); model.addDumpFieldVector("displacement"); model.addDumpField("residual"); model.addDumpField("partitions"); model.dump(); model.setBaseNameToDumper("cohesive elements", "cohesive_elements_parallel_tetrahedron"); model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.dump("cohesive elements"); /// find elements to displace ElementTypeMapArray<UInt> elements("elements", ""); findElementsToDisplace(mesh, elements); UInt nb_elements_check = elements(type).getSize(); comm.allReduce(&nb_elements_check, 1, _so_sum); if (nb_elements_check != nb_elements_check_serial) { if (prank == 0) { std::cout << "Error: number of elements to check is wrong" << std::endl; std::cout << "Serial: " << nb_elements_check_serial << " Parallel: " << nb_elements_check << std::endl; } finalize(); return EXIT_FAILURE; } /// find nodes to check Array<UInt> nodes_to_check; findNodesToCheck(mesh, elements, nodes_to_check, psize); Vector<Int> nodes_to_check_size(psize); nodes_to_check_size(prank) = nodes_to_check.getSize(); comm.allGather(nodes_to_check_size.storage(), 1); UInt nodes_to_check_global_size = std::accumulate(nodes_to_check_size.storage(), nodes_to_check_size.storage() + psize, 0); if (nodes_to_check_global_size != nb_nodes_to_check_serial) { if (prank == 0) { std::cout << "Error: number of nodes to check is wrong in parallel" << std::endl; std::cout << "Serial: " << nb_nodes_to_check_serial << " Parallel: " << nodes_to_check_global_size << std::endl; } finalize(); return EXIT_FAILURE; } /// rotate mesh Real angle = 1.; Matrix<Real> rotation(spatial_dimension, spatial_dimension); rotation.clear(); rotation(0, 0) = std::cos(angle); rotation(0, 1) = std::sin(angle) * -1.; rotation(1, 0) = std::sin(angle); rotation(1, 1) = std::cos(angle); rotation(2, 2) = 1.; Vector<Real> increment_tmp(spatial_dimension); for (UInt dim = 0; dim < spatial_dimension; ++dim) { increment_tmp(dim) = (dim + 1) * increment_constant; } Vector<Real> increment(spatial_dimension); increment.mul<false>(rotation, increment_tmp); Array<Real> & position = mesh.getNodes(); Array<Real> position_tmp(position); Array<Real>::iterator<Vector<Real> > position_it = position.begin(spatial_dimension); Array<Real>::iterator<Vector<Real> > position_end = position.end(spatial_dimension); Array<Real>::iterator<Vector<Real> > position_tmp_it = position_tmp.begin(spatial_dimension); for (; position_it != position_end; ++position_it, ++position_tmp_it) position_it->mul<false>(rotation, *position_tmp_it); model.dump(); model.dump("cohesive elements"); updateDisplacement(model, elements, increment); Real theoretical_Ed = 0; Vector<Real> opening(spatial_dimension); Vector<Real> traction(spatial_dimension); Vector<Real> opening_old(spatial_dimension); Vector<Real> traction_old(spatial_dimension); opening.clear(); traction.clear(); opening_old.clear(); traction_old.clear(); Vector<Real> Dt(spatial_dimension); Vector<Real> Do(spatial_dimension); const Array<Real> & residual = model.getResidual(); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { model.updateResidual(); opening += increment_tmp; if (checkTractions(model, opening, traction, rotation) || checkEquilibrium(mesh, residual) || checkResidual(residual, traction, nodes_to_check, rotation)) { finalize(); return EXIT_FAILURE; } /// compute energy Do = opening; Do -= opening_old; Dt = traction_old; Dt += traction; theoretical_Ed += .5 * Do.dot(Dt); opening_old = opening; traction_old = traction; updateDisplacement(model, elements, increment); if(s % 10 == 0) { if (prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; model.dump(); model.dump("cohesive elements"); } } model.dump(); model.dump("cohesive elements"); Real Ed = model.getEnergy("dissipated"); theoretical_Ed *= 4.; if (prank == 0) std::cout << "Dissipated energy: " << Ed << ", theoretical value: " << theoretical_Ed << std::endl; if (!Math::are_float_equal(Ed, theoretical_Ed) || std::isnan(Ed)) { if (prank == 0) std::cout << "Error: the dissipated energy is incorrect" << std::endl; finalize(); return EXIT_FAILURE; } finalize(); if(prank == 0) std::cout << "OK: Test passed!" << std::endl; return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ void updateDisplacement(SolidMechanicsModelCohesive & model, const ElementTypeMapArray<UInt> & elements, Vector<Real> & increment) { UInt spatial_dimension = model.getSpatialDimension(); Mesh & mesh = model.getFEEngine().getMesh(); UInt nb_nodes = mesh.getNbNodes(); Array<Real> & displacement = model.getDisplacement(); Array<bool> update(nb_nodes); update.clear(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type); for (; it != last; ++it) { ElementType type = *it; const Array<UInt> & elem = elements(type, ghost_type); const Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_nodes_per_element = connectivity.getNbComponent(); for (UInt el = 0; el < elem.getSize(); ++el) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity(elem(el), n); if (!update(node)) { Vector<Real> node_disp(displacement.storage() + node * spatial_dimension, spatial_dimension); node_disp += increment; update(node) = true; } } } } } } /* -------------------------------------------------------------------------- */ bool checkTractions(SolidMechanicsModelCohesive & model, Vector<Real> & opening, Vector<Real> & theoretical_traction, Matrix<Real> & rotation) { UInt spatial_dimension = model.getSpatialDimension(); const Mesh & mesh = model.getMesh(); const MaterialCohesive & mat_cohesive = dynamic_cast < const MaterialCohesive & > (model.getMaterial(1)); Real sigma_c = mat_cohesive.getParam< RandomInternalField<Real, FacetInternalField> >("sigma_c"); const Real beta = mat_cohesive.getParam<Real>("beta"); const Real G_cI = mat_cohesive.getParam<Real>("G_c"); // Real G_cII = mat_cohesive.getParam<Real>("G_cII"); const Real delta_0 = mat_cohesive.getParam<Real>("delta_0"); const Real kappa = mat_cohesive.getParam<Real>("kappa"); Real delta_c = 2 * G_cI / sigma_c; sigma_c *= delta_c / (delta_c - delta_0); Vector<Real> normal_opening(spatial_dimension); normal_opening.clear(); normal_opening(0) = opening(0); Real normal_opening_norm = normal_opening.norm(); Vector<Real> tangential_opening(spatial_dimension); tangential_opening.clear(); for (UInt dim = 1; dim < spatial_dimension; ++dim) tangential_opening(dim) = opening(dim); Real tangential_opening_norm = tangential_opening.norm(); Real beta2_kappa2 = beta * beta/kappa/kappa; Real beta2_kappa = beta * beta/kappa; Real delta = std::sqrt(tangential_opening_norm * tangential_opening_norm * beta2_kappa2 + normal_opening_norm * normal_opening_norm); delta = std::max(delta, delta_0); Real theoretical_damage = std::min(delta / delta_c, 1.); if (Math::are_float_equal(theoretical_damage, 1.)) theoretical_traction.clear(); else { theoretical_traction = tangential_opening; theoretical_traction *= beta2_kappa; theoretical_traction += normal_opening; theoretical_traction *= sigma_c / delta * (1. - theoretical_damage); } Vector<Real> theoretical_traction_rotated(spatial_dimension); theoretical_traction_rotated.mul<false>(rotation, theoretical_traction); // adjust damage theoretical_damage = std::max((delta - delta_0) / (delta_c - delta_0), 0.); theoretical_damage = std::min(theoretical_damage, 1.); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); for (; it != last; ++it) { ElementType type = *it; const Array<Real> & traction = mat_cohesive.getTraction(type, ghost_type); const Array<Real> & damage = mat_cohesive.getDamage(type, ghost_type); UInt nb_quad_per_el = model.getFEEngine("CohesiveFEEngine").getNbIntegrationPoints(type); UInt nb_element = model.getMesh().getNbElement(type, ghost_type); UInt tot_nb_quad = nb_element * nb_quad_per_el; for (UInt q = 0; q < tot_nb_quad; ++q) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { if (!Math::are_float_equal(std::abs(theoretical_traction_rotated(dim)), std::abs(traction(q, dim)))) { std::cout << "Error: tractions are incorrect" << std::endl; return 1; } } if (ghost_type == _not_ghost) if (!Math::are_float_equal(theoretical_damage, damage(q))) { std::cout << "Error: damage is incorrect" << std::endl; return 1; } } } } return 0; } /* -------------------------------------------------------------------------- */ void findNodesToCheck(const Mesh & mesh, const ElementTypeMapArray<UInt> & elements, Array<UInt> & nodes_to_check, Int psize) { - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); nodes_to_check.resize(0); Array<UInt> global_nodes_to_check; UInt spatial_dimension = mesh.getSpatialDimension(); const Array<Real> & position = mesh.getNodes(); UInt nb_nodes = position.getSize(); Array<bool> checked_nodes(nb_nodes); checked_nodes.clear(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); for (; it != last; ++it) { ElementType type = *it; const Array<UInt> & elem = elements(type); const Array<UInt> & connectivity = mesh.getConnectivity(type); UInt nb_nodes_per_elem = connectivity.getNbComponent(); for (UInt el = 0; el < elem.getSize(); ++el) { UInt element = elem(el); Vector<UInt> conn_el(connectivity.storage() + nb_nodes_per_elem * element, nb_nodes_per_elem); for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = conn_el(n); if (std::abs(position(node, 0) - 0.) < 1.e-6 && !checked_nodes(node)) { checked_nodes(node) = true; nodes_to_check.push_back(node); global_nodes_to_check.push_back(mesh.getNodeGlobalId(node)); } } } } std::vector<CommunicationRequest *> requests; for (Int p = prank + 1; p < psize; ++p) { requests.push_back(comm.asyncSend(global_nodes_to_check.storage(), global_nodes_to_check.getSize(), p, prank)); } Array<UInt> recv_nodes; for (Int p = 0; p < prank; ++p) { CommunicationStatus status; comm.probe<UInt>(p, p, status); UInt recv_nodes_size = recv_nodes.getSize(); recv_nodes.resize(recv_nodes_size + status.getSize()); comm.receive(recv_nodes.storage() + recv_nodes_size, status.getSize(), p, p); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); for (UInt i = 0; i < recv_nodes.getSize(); ++i) { Array<UInt>::iterator<UInt> node_position = std::find(global_nodes_to_check.begin(), global_nodes_to_check.end(), recv_nodes(i)); if (node_position != global_nodes_to_check.end()) { UInt index = node_position - global_nodes_to_check.begin(); nodes_to_check.erase(index); global_nodes_to_check.erase(index); } } } /* -------------------------------------------------------------------------- */ bool checkEquilibrium(const Mesh & mesh, const Array<Real> & residual) { UInt spatial_dimension = residual.getNbComponent(); Vector<Real> residual_sum(spatial_dimension); residual_sum.clear(); Array<Real>::const_iterator<Vector<Real> > res_it = residual.begin(spatial_dimension); for (UInt n = 0; n < residual.getSize(); ++n, ++res_it) { if (mesh.isLocalOrMasterNode(n)) residual_sum += *res_it; } - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); comm.allReduce(residual_sum.storage(), spatial_dimension, _so_sum); for (UInt s = 0; s < spatial_dimension; ++s) { if (!Math::are_float_equal(residual_sum(s), 0.)) { if (comm.whoAmI() == 0) std::cout << "Error: system is not in equilibrium!" << std::endl; return 1; } } return 0; } /* -------------------------------------------------------------------------- */ bool checkResidual(const Array<Real> & residual, const Vector<Real> & traction, const Array<UInt> & nodes_to_check, const Matrix<Real> & rotation) { UInt spatial_dimension = residual.getNbComponent(); Vector<Real> total_force(spatial_dimension); total_force.clear(); for (UInt n = 0; n < nodes_to_check.getSize(); ++n) { UInt node = nodes_to_check(n); Vector<Real> res(residual.storage() + node * spatial_dimension, spatial_dimension); total_force += res; } - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); comm.allReduce(total_force.storage(), spatial_dimension, _so_sum); Vector<Real> theoretical_total_force(spatial_dimension); theoretical_total_force.mul<false>(rotation, traction); theoretical_total_force *= -1 * 2 * 2; for (UInt s = 0; s < spatial_dimension; ++s) { if (!Math::are_float_equal(total_force(s), theoretical_total_force(s))) { if (comm.whoAmI() == 0) std::cout << "Error: total force isn't correct!" << std::endl; return 1; } } return 0; } /* -------------------------------------------------------------------------- */ void findElementsToDisplace(const Mesh & mesh, ElementTypeMapArray<UInt> & elements) { UInt spatial_dimension = mesh.getSpatialDimension(); mesh.initElementTypeMapArray(elements, 1, spatial_dimension); Vector<Real> bary(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type); for (; it != last; ++it) { ElementType type = *it; Array<UInt> & elem = elements(type, ghost_type); UInt nb_element = mesh.getNbElement(type, ghost_type); for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, bary.storage(), ghost_type); if (bary(0) > 0.0001) elem.push_back(el); } } } } diff --git a/test/test_solver/test_petsc_matrix_apply_boundary.cc b/test/test_solver/test_petsc_matrix_apply_boundary.cc index 57b7eeb7b..c89eebdf2 100644 --- a/test/test_solver/test_petsc_matrix_apply_boundary.cc +++ b/test/test_solver/test_petsc_matrix_apply_boundary.cc @@ -1,144 +1,144 @@ /** * @file test_petsc_matrix_apply_boundary.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Mon Oct 13 2014 * @date last modification: Wed Oct 28 2015 * * @brief test the applyBoundary method of the PETScMatrix class * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <cstdlib> /* -------------------------------------------------------------------------- */ -#include "static_communicator.hh" +#include "communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; - StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = akantu::Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ ElementSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("triangle.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); // fill the matrix with UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; SparseMatrix K(nb_global_nodes * spatial_dimension, _symmetric); K.buildProfile(mesh, dof_synchronizer, spatial_dimension); Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type); // create petsc matrix PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _symmetric); petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); // add stiffness matrix to petsc matrix petsc_matrix.add(K, 1); // create boundary array: block all dofs UInt nb_nodes = mesh.getNbNodes(); Array<bool> boundary = Array<bool>(nb_nodes, spatial_dimension, true); // apply boundary petsc_matrix.applyBoundary(boundary); // test if all entries except the diagonal ones have been zeroed Real test_passed = 0; for (UInt i = 0; i < nb_nodes * spatial_dimension; ++i) { if (dof_synchronizer.isLocalOrMasterDOF(i)) { for (UInt j = 0; j < nb_nodes * spatial_dimension; ++j) { if (dof_synchronizer.isLocalOrMasterDOF(j)) { if (i == j) test_passed += petsc_matrix(i, j) - 1; else test_passed += petsc_matrix(i, j) - 0; } } } } if (std::abs(test_passed) > Math::getTolerance()) { finalize(); return EXIT_FAILURE; } delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_petsc_matrix_diagonal.cc b/test/test_solver/test_petsc_matrix_diagonal.cc index c0cb48b96..145105038 100644 --- a/test/test_solver/test_petsc_matrix_diagonal.cc +++ b/test/test_solver/test_petsc_matrix_diagonal.cc @@ -1,151 +1,151 @@ /** * @file test_petsc_matrix_diagonal.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Mon Oct 13 2014 * @date last modification: Fri Jan 15 2016 * * @brief test the connectivity is correctly represented in the PETScMatrix * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <iostream> /* -------------------------------------------------------------------------- */ -#include "static_communicator.hh" +#include "communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" #include "dumper_paraview.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; - StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = akantu::Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ ElementSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("triangle.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } // DumperParaview mesh_dumper("mesh_dumper"); // mesh_dumper.registerMesh(mesh, spatial_dimension, _not_ghost); // mesh_dumper.dump(); /// initialize the FEEngine and the dof_synchronizer FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); // construct an Akantu sparse matrix, build the profile and fill the matrix for the given mesh UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; SparseMatrix K_akantu(nb_global_nodes * spatial_dimension, _unsymmetric); K_akantu.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// use as elemental matrices a matrix with values equal to 1 every where Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1.); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix fem->assembleMatrix(K_e, K_akantu, spatial_dimension, element_type, ghost_type); /// construct a PETSc matrix PETScMatrix K_petsc(nb_global_nodes * spatial_dimension, _unsymmetric); /// build the profile of the PETSc matrix for the mesh of this example K_petsc.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// add an Akantu sparse matrix to a PETSc sparse matrix K_petsc.add(K_akantu, 1); /// check to how many elements each node is connected CSR<Element> node_to_elem; MeshUtils::buildNode2Elements(mesh, node_to_elem, spatial_dimension); /// test the diagonal of the PETSc matrix: the diagonal entries /// of the PETSc matrix correspond to the number of elements /// connected to the node of the dof. Note: for an Akantu matrix this is only true for the serial case Real error = 0.; /// loop over all diagonal values of the matrix for (UInt i = 0; i < mesh.getNbNodes(); ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { UInt dof = i * spatial_dimension + j; /// for PETSc matrix only DOFs on the processor and be accessed if (dof_synchronizer.isLocalOrMasterDOF(dof)) { UInt global_dof = dof_synchronizer.getDOFGlobalID(dof); std::cout << "Number of elements connected: " << node_to_elem.getNbCols(i) << std::endl; std::cout << "K_petsc(" << global_dof << "," << global_dof << ")=" << K_petsc(dof,dof) << std::endl; error += std::abs(K_petsc(dof, dof) - node_to_elem.getNbCols(i)); } } } if(error > Math::getTolerance() ) { std::cout << "error in the stiffness matrix!!!" << std::endl; finalize(); return EXIT_FAILURE; } delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_petsc_matrix_profile.cc b/test/test_solver/test_petsc_matrix_profile.cc index 35439d340..391f22855 100644 --- a/test/test_solver/test_petsc_matrix_profile.cc +++ b/test/test_solver/test_petsc_matrix_profile.cc @@ -1,134 +1,134 @@ /** * @file test_petsc_matrix_profile.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Mon Oct 13 2014 * @date last modification: Tue Apr 28 2015 * * @brief test the profile generation of the PETScMatrix class * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <cstdlib> #include <fstream> /* -------------------------------------------------------------------------- */ -#include "static_communicator.hh" +#include "communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" /// #include "dumper_paraview.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; - StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = akantu::Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ ElementSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("square.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } // dump mesh in paraview // DumperParaview mesh_dumper("mesh_dumper"); // mesh_dumper.registerMesh(mesh, spatial_dimension, _not_ghost); // mesh_dumper.dump(); /// initialize the FEEngine and the dof_synchronizer FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); // construct an Akantu sparse matrix, build the profile and fill the matrix for the given mesh UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; SparseMatrix K_akantu(nb_global_nodes * spatial_dimension, _unsymmetric); K_akantu.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// use as elemental matrices a matrix with values equal to 1 every where Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1.); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix fem->assembleMatrix(K_e, K_akantu, spatial_dimension, element_type, ghost_type); /// construct a PETSc matrix PETScMatrix K_petsc(nb_global_nodes * spatial_dimension, _unsymmetric); /// build the profile of the PETSc matrix for the mesh of this example K_petsc.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// add an Akantu sparse matrix to a PETSc sparse matrix K_petsc.add(K_akantu, 1); /// save the profile K_petsc.saveMatrix("profile.txt"); /// print the matrix to screen std::ifstream profile; profile.open("profile.txt"); std::string current_line; while(getline(profile, current_line)) std::cout << current_line << std::endl; profile.close(); delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_petsc_matrix_profile_parallel.cc b/test/test_solver/test_petsc_matrix_profile_parallel.cc index 5d750d5d1..b638a3c23 100644 --- a/test/test_solver/test_petsc_matrix_profile_parallel.cc +++ b/test/test_solver/test_petsc_matrix_profile_parallel.cc @@ -1,135 +1,135 @@ /** * @file test_petsc_matrix_profile_parallel.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Mon Oct 13 2014 * @date last modification: Tue Apr 28 2015 * * @brief test the profile generation of the PETScMatrix class in parallel * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <cstdlib> #include <fstream> /* -------------------------------------------------------------------------- */ -#include "static_communicator.hh" +#include "communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" /// #include "dumper_paraview.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; - StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = akantu::Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ ElementSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("square.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } // dump mesh in paraview // DumperParaview mesh_dumper("mesh_dumper"); // mesh_dumper.registerMesh(mesh, spatial_dimension, _not_ghost); // mesh_dumper.dump(); /// initialize the FEEngine and the dof_synchronizer FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); // construct an Akantu sparse matrix, build the profile and fill the matrix for the given mesh UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; SparseMatrix K_akantu(nb_global_nodes * spatial_dimension, _unsymmetric); K_akantu.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// use as elemental matrices a matrix with values equal to 1 every where Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1.); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix fem->assembleMatrix(K_e, K_akantu, spatial_dimension, element_type, ghost_type); /// construct a PETSc matrix PETScMatrix K_petsc(nb_global_nodes * spatial_dimension, _unsymmetric); /// build the profile of the PETSc matrix for the mesh of this example K_petsc.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// add an Akantu sparse matrix to a PETSc sparse matrix K_petsc.add(K_akantu, 1); /// save the profile K_petsc.saveMatrix("profile_parallel.txt"); /// print the matrix to screen if(prank == 0) { std::ifstream profile; profile.open("profile_parallel.txt"); std::string current_line; while(getline(profile, current_line)) std::cout << current_line << std::endl; profile.close(); } delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_solver_petsc.cc b/test/test_solver/test_solver_petsc.cc index cddc54227..4c754b6cc 100644 --- a/test/test_solver/test_solver_petsc.cc +++ b/test/test_solver/test_solver_petsc.cc @@ -1,165 +1,165 @@ /** * @file test_solver_petsc.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Mon Oct 13 2014 * @date last modification: Wed Oct 28 2015 * * @brief test the PETSc solver interface * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include <cstdlib> /* -------------------------------------------------------------------------- */ -#include "static_communicator.hh" +#include "communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "petsc_matrix.hh" #include "solver_petsc.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _segment_2; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 1; - StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = akantu::Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ ElementSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("1D_bar.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); // fill the matrix with UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; SparseMatrix K(nb_global_nodes * spatial_dimension, _symmetric); K.buildProfile(mesh, dof_synchronizer, spatial_dimension); Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 0); for (UInt i = 0; i < nb_dofs_per_element; ++i) { for (UInt j = 0; j < nb_dofs_per_element; ++j) { element_input(i, j) = ((i == j) ? 1 : -1); } } Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type); // apply boundary: block first node const Array<Real> & position = mesh.getNodes(); UInt nb_nodes = mesh.getNbNodes(); Array<bool> boundary = Array<bool>(nb_nodes, spatial_dimension, false); for (UInt i = 0; i < nb_nodes; ++i) { if (std::abs(position(i, 0)) < Math::getTolerance() ) boundary(i, 0) = true; } K.applyBoundary(boundary); /// create the PETSc matrix for the solve step PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _symmetric); petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// copy the stiffness matrix into the petsc matrix petsc_matrix.add(K, 1); // initialize internal forces: they are zero because imposed displacement is zero Array<Real> internal_forces(nb_nodes, spatial_dimension, 0.); // compute residual: apply nodal force on last node Array<Real> residual(nb_nodes, spatial_dimension, 0.); for (UInt i = 0; i < nb_nodes; ++i) { if (std::abs(position(i, 0) - 10) < Math::getTolerance() ) residual(i, 0) += 2; } residual -= internal_forces; /// initialize solver and solution Array<Real> solution(nb_nodes, spatial_dimension, 0.); SolverPETSc solver(petsc_matrix); solver.initialize(); solver.setOperators(); solver.setRHS(residual); solver.solve(solution); /// verify solution Math::setTolerance(1e-11); for (UInt i = 0; i < nb_nodes; ++i) { if (!dof_synchronizer.isPureGhostDOF(i) && !Math::are_float_equal(2 * position(i, 0), solution(i, 0))) { std::cout << "The solution is not correct!!!!" << std::endl; finalize(); return EXIT_FAILURE; } } delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_sparse_matrix_product.cc b/test/test_solver/test_sparse_matrix_product.cc index e08961cc2..ce24921de 100644 --- a/test/test_solver/test_sparse_matrix_product.cc +++ b/test/test_solver/test_sparse_matrix_product.cc @@ -1,115 +1,115 @@ /** * @file test_sparse_matrix_product.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 17 2011 * @date last modification: Sun Oct 19 2014 * * @brief test the matrix vector product in parallel * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <iostream> /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_partition_scotch.hh" #include "element_synchronizer.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { initialize(argc, argv); const UInt spatial_dimension = 2; const UInt nb_dof = 2; - StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); Mesh mesh(spatial_dimension); mesh.read("bar.msh"); mesh.distribute(); UInt nb_nodes = mesh.getNbNodes(); DOFManagerDefault dof_manager(mesh, "test_dof_manager"); Array<Real> test_synchronize(nb_nodes, nb_dof, "Test vector"); dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal); if (prank == 0) std::cout << "Creating a SparseMatrix" << std::endl; auto & A = dof_manager.getNewMatrix("A", _symmetric); Array<Real> dof_vector(nb_nodes, nb_dof, "vector"); if (prank == 0) std::cout << "Filling the matrix" << std::endl; for (UInt i = 0; i < nb_nodes*nb_dof; ++i) { if(dof_manager.isLocalOrMasterDOF(i)) A.add(i, i, 2.); } std::stringstream str; str << "Matrix_" << prank << ".mtx"; A.saveMatrix(str.str()); for (UInt n = 0; n < nb_nodes; ++n) { for (UInt d = 0; d < nb_dof; ++d) { dof_vector(n, d) = 1.; } } if (prank == 0) std::cout << "Computing x = A * x" << std::endl; dof_vector *= A; auto & sync = dynamic_cast<DOFManagerDefault &>(dof_manager) .getSynchronizer(); if (prank == 0) std::cout << "Gathering the results on proc 0" << std::endl; if(psize > 1) { if(prank == 0) { Array<Real> gathered; sync.gather(dof_vector, gathered); debug::setDebugLevel(dblTest); std::cout << gathered << std::endl; debug::setDebugLevel(dblWarning); } else { sync.gather(dof_vector); } } else { debug::setDebugLevel(dblTest); std::cout << dof_vector << std::endl; debug::setDebugLevel(dblWarning); } finalize(); return 0; } diff --git a/test/test_solver/test_sparse_matrix_profile_parallel.cc b/test/test_solver/test_sparse_matrix_profile_parallel.cc index 4ea513a55..67682f43b 100644 --- a/test/test_solver/test_sparse_matrix_profile_parallel.cc +++ b/test/test_solver/test_sparse_matrix_profile_parallel.cc @@ -1,114 +1,114 @@ /** * @file test_sparse_matrix_profile_parallel.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Sun Sep 12 2010 * @date last modification: Sun Oct 19 2014 * * @brief test the sparse matrix class in parallel * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io_msh.hh" #include "mesh_partition_scotch.hh" #include "communicator.hh" #include "sparse_matrix.hh" #include "solver_mumps.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { akantu::initialize(argc, argv); int dim = 2; //#ifdef AKANTU_USE_IOHELPER //akantu::ElementType type = akantu::_triangle_6; //#endif //AKANTU_USE_IOHELPER akantu::Mesh mesh(dim); // akantu::debug::setDebugLevel(akantu::dblDump); - akantu::StaticCommunicator * comm = akantu::StaticCommunicator::getStaticCommunicator(); + akantu::StaticCommunicator * comm = akantu::Communicator::getStaticCommunicator(); akantu::Int psize = comm->getNbProc(); akantu::Int prank = comm->whoAmI(); akantu::UInt n = 0; /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ akantu::Communicator * communicator; if(prank == 0) { akantu::MeshIOMSH mesh_io; mesh_io.read("triangle.msh", mesh); akantu::MeshPartition * partition = new akantu::MeshPartitionScotch(mesh, dim); // partition->reorder(); mesh_io.write("triangle_reorder.msh", mesh); n = mesh.getNbNodes(); partition->partitionate(psize); communicator = akantu::Communicator::createCommunicatorDistributeMesh(mesh, partition); delete partition; } else { communicator = akantu::Communicator::createCommunicatorDistributeMesh(mesh, NULL); } std::cout << "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " << mesh.getNbGlobalNodes() << std::endl; akantu::SparseMatrix sparse_matrix(mesh, akantu::_symmetric, 2, "mesh"); sparse_matrix.buildProfile(); akantu::Solver * solver = new akantu::SolverMumps(sparse_matrix); if(prank == 0) { for(akantu::UInt i = 0; i < n; ++i) { solver->getRHS().storage()[i] = 1.; } } akantu::debug::setDebugLevel(akantu::dblDump); solver->initialize(); std::stringstream sstr; sstr << "profile_" << prank << ".mtx"; sparse_matrix.saveProfile(sstr.str()); akantu::finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_sparse_solver_mumps.cc b/test/test_solver/test_sparse_solver_mumps.cc index b8ff41186..b3ba6aaf8 100644 --- a/test/test_solver/test_sparse_solver_mumps.cc +++ b/test/test_solver/test_sparse_solver_mumps.cc @@ -1,159 +1,158 @@ /** * @file test_sparse_matrix_product.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 17 2011 * @date last modification: Sun Oct 19 2014 * * @brief test the matrix vector product in parallel * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dof_synchronizer.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_accessor.hh" #include "mesh_partition_scotch.hh" #include "sparse_matrix_aij.hh" #include "sparse_solver_mumps.hh" #include "terms_to_assemble.hh" /* -------------------------------------------------------------------------- */ #include <iostream> /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ void genMesh(Mesh & mesh, UInt nb_nodes); /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { initialize(argc, argv); const UInt spatial_dimension = 1; const UInt nb_global_dof = 11; - StaticCommunicator & comm = - akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); // Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); Mesh mesh(spatial_dimension); if (prank == 0) { genMesh(mesh, nb_global_dof); RandomGenerator<UInt>::seed(1496137735); } else { RandomGenerator<UInt>::seed(2992275470); } mesh.distribute(); UInt node = 0; for (auto pos : mesh.getNodes()) { std::cout << prank << " " << node << " pos: " << pos << " [" << mesh.getNodeGlobalId(node) << "] " << mesh.getNodeType(node) << std::endl; ++node; } UInt nb_nodes = mesh.getNbNodes(); DOFManagerDefault dof_manager(mesh, "test_dof_manager"); Array<Real> x(nb_nodes); dof_manager.registerDOFs("x", x, _dst_nodal); const auto & local_equation_number = dof_manager.getEquationsNumbers("x"); auto & A = dof_manager.getNewMatrix("A", _symmetric); Array<Real> b(nb_nodes); TermsToAssemble terms; for (UInt i = 0; i < nb_nodes; ++i) { if (dof_manager.isLocalOrMasterDOF(i)) { auto li = local_equation_number(i); auto gi = dof_manager.localToGlobalEquationNumber(li); terms(i, i) = 1. / (1. + gi); } } dof_manager.assemblePreassembledMatrix("x", "x", "A", terms); std::stringstream str; str << "Matrix_" << prank << ".mtx"; A.saveMatrix(str.str()); for (UInt n = 0; n < nb_nodes; ++n) { b(n) = 1.; } SparseSolverMumps solver(dof_manager, "A"); solver.solve(x, b); auto & sync = dynamic_cast<DOFManagerDefault &>(dof_manager).getSynchronizer(); if (prank == 0) { Array<Real> x_gathered(dof_manager.getSystemSize()); sync.gather(x, x_gathered); debug::setDebugLevel(dblTest); std::cout << x_gathered << std::endl; debug::setDebugLevel(dblWarning); UInt d = 1.; for (auto x : x_gathered) { if (std::abs(x - d) / d > 1e-15) AKANTU_EXCEPTION("Error in the solution: " << x << " != " << d << " [" << (std::abs(x - d) / d) << "]."); ++d; } } else { sync.gather(x); } finalize(); return 0; } /* -------------------------------------------------------------------------- */ void genMesh(Mesh & mesh, UInt nb_nodes) { MeshAccessor mesh_accessor(mesh); Array<Real> & nodes = mesh_accessor.getNodes(); Array<UInt> & conn = mesh_accessor.getConnectivity(_segment_2); nodes.resize(nb_nodes); for (UInt n = 0; n < nb_nodes; ++n) { nodes(n, _x) = n * (1. / (nb_nodes - 1)); } conn.resize(nb_nodes - 1); for (UInt n = 0; n < nb_nodes - 1; ++n) { conn(n, 0) = n; conn(n, 1) = n + 1; } } diff --git a/test/test_synchronizer/test_data_distribution.cc b/test/test_synchronizer/test_data_distribution.cc index b5f970ae0..59ba6be9b 100644 --- a/test/test_synchronizer/test_data_distribution.cc +++ b/test/test_synchronizer/test_data_distribution.cc @@ -1,173 +1,173 @@ /** * @file test_data_distribution.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Sep 05 2014 * @date last modification: Sun Oct 19 2014 * * @brief Test the mesh distribution on creation of a distributed synchonizer * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "aka_random_generator.hh" #include "element_group.hh" #include "element_synchronizer.hh" #include "mesh_iterators.hh" #include "mesh_partition_mesh_data.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char * argv[]) { initialize(argc, argv); const UInt spatial_dimension = 3; Mesh mesh_group_after(spatial_dimension, "after"); Mesh mesh_group_before(spatial_dimension, "before"); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); if (prank == 0) { mesh_group_before.read("data_split.msh"); mesh_group_after.read("data_split.msh"); mesh_group_before.registerData<UInt>("global_id"); mesh_group_after.registerData<UInt>("global_id"); for (const auto & type : mesh_group_after.elementTypes(_all_dimensions)) { auto & gidb = mesh_group_before.getDataPointer<UInt>("global_id", type); auto & gida = mesh_group_after.getDataPointer<UInt>("global_id", type); for (auto && data : zip(arange(gida.size()), gida, gidb)) { std::get<1>(data) = std::get<0>(data); std::get<2>(data) = std::get<0>(data); } } } RandomGenerator<UInt>::seed(1); mesh_group_before.distribute(); RandomGenerator<UInt>::seed(1); mesh_group_after.distribute(); if (prank == 0) std::cout << mesh_group_after; for (const auto & agrp : ElementGroupsIterable(mesh_group_after)) { const ElementGroup & bgrp = mesh_group_before.getElementGroup(agrp.getName()); for (auto && ghost_type : ghost_types) { for (const auto & type : bgrp.elementTypes(_all_dimensions, ghost_type)) { Array<UInt> & gidb = mesh_group_before.getDataPointer<UInt>( "global_id", type, ghost_type); Array<UInt> & gida = mesh_group_after.getDataPointer<UInt>( "global_id", type, ghost_type); Array<UInt> bgelem(bgrp.getElements(type, ghost_type)); Array<UInt> agelem(agrp.getElements(type, ghost_type)); std::transform(agelem.begin(), agelem.end(), agelem.begin(), [&gida](auto & i) { return gida(i); }); std::transform(bgelem.begin(), bgelem.end(), bgelem.begin(), [&gidb](auto & i) { return gidb(i); }); std::sort(bgelem.begin(), bgelem.end()); std::sort(agelem.begin(), agelem.end()); if (not std::equal(bgelem.begin(), bgelem.end(), agelem.begin())) { std::cerr << "The filters array for the group " << agrp.getName() << " and for the element type " << type << ", " << ghost_type << " do not match" << std::endl; debug::setDebugLevel(dblTest); std::cerr << bgelem << std::endl; std::cerr << agelem << std::endl; debug::debugger.exit(EXIT_FAILURE); } } } } for (const auto & agrp : NodeGroupsIterable(mesh_group_after)) { const NodeGroup & bgrp = mesh_group_before.getNodeGroup(agrp.getName()); const Array<UInt> & gidb = mesh_group_before.getGlobalNodesIds(); const Array<UInt> & gida = mesh_group_after.getGlobalNodesIds(); Array<UInt> bgnode(0, 1); Array<UInt> agnode(0, 1); for (auto && pair : zip(bgrp, agrp)) { UInt a,b; std::tie(b, a) = pair; if (psize > 1) { if (mesh_group_before.isLocalOrMasterNode(b)) bgnode.push_back(gidb(b)); if (mesh_group_after.isLocalOrMasterNode(a)) agnode.push_back(gida(a)); } } std::sort(bgnode.begin(), bgnode.end()); std::sort(agnode.begin(), agnode.end()); if (!std::equal(bgnode.begin(), bgnode.end(), agnode.begin())) { std::cerr << "The filters array for the group " << agrp.getName() << " do not match" << std::endl; debug::setDebugLevel(dblTest); std::cerr << bgnode << std::endl; std::cerr << agnode << std::endl; debug::debugger.exit(EXIT_FAILURE); } } mesh_group_after.getElementGroup("inside").setBaseName("after_inside"); mesh_group_after.getElementGroup("inside").dump(); mesh_group_after.getElementGroup("outside").setBaseName("after_outside"); mesh_group_after.getElementGroup("outside").dump(); mesh_group_after.getElementGroup("volume").setBaseName("after_volume"); mesh_group_after.getElementGroup("volume").dump(); mesh_group_before.getElementGroup("inside").setBaseName("before_inside"); mesh_group_before.getElementGroup("inside").dump(); mesh_group_before.getElementGroup("outside").setBaseName("before_outside"); mesh_group_before.getElementGroup("outside").dump(); mesh_group_before.getElementGroup("volume").setBaseName("before_volume"); mesh_group_before.getElementGroup("volume").dump(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_synchronizer/test_dof_synchronizer.cc b/test/test_synchronizer/test_dof_synchronizer.cc index 70fcb3c34..aab3c5d66 100644 --- a/test/test_synchronizer/test_dof_synchronizer.cc +++ b/test/test_synchronizer/test_dof_synchronizer.cc @@ -1,149 +1,149 @@ /** * @file test_dof_synchronizer.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 17 2011 * @date last modification: Sun Oct 19 2014 * * @brief Test the functionality of the DOFSynchronizer class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dof_synchronizer.hh" #include "element_synchronizer.hh" #include "mesh_io.hh" #include "mesh_partition_scotch.hh" -#include "static_communicator.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "io_helper.hh" #endif // AKANTU_USE_IOHELPER /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char * argv[]) { const UInt spatial_dimension = 2; initialize(argc, argv); - StaticCommunicator & comm = - akantu::StaticCommunicator::getStaticCommunicator(); + const auto & comm = + akantu::Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); Mesh mesh(spatial_dimension); if (prank == 0) mesh.read("bar.msh"); mesh.distribute(); DOFManagerDefault dof_manager(mesh, "test_dof_manager"); UInt nb_nodes = mesh.getNbNodes(); /* ------------------------------------------------------------------------ */ /* test the synchronization */ /* ------------------------------------------------------------------------ */ Array<Real> test_synchronize(nb_nodes, spatial_dimension, "Test vector"); dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal); auto & equation_number = dof_manager.getLocalEquationNumbers("test_synchronize"); DOFSynchronizer & dof_synchronizer = dof_manager.getSynchronizer(); std::cout << "Synchronizing a dof vector" << std::endl; Array<Int> local_data_array(dof_manager.getLocalSystemSize(), 2); auto it_data = local_data_array.begin(2); for (UInt local_dof = 0; local_dof < dof_manager.getLocalSystemSize(); ++local_dof) { UInt equ_number = equation_number(local_dof); Vector<Int> val; if (dof_manager.isLocalOrMasterDOF(equ_number)) { UInt global_dof = dof_manager.localToGlobalEquationNumber(local_dof); val = {0, 1}; val += global_dof * 2; } else { val = {-1, -1}; } Vector<Int> data = it_data[local_dof]; data = val; } dof_synchronizer.synchronize(local_data_array); auto test_data = [&]() -> void { auto it_data = local_data_array.begin(2); for (UInt local_dof = 0; local_dof < dof_manager.getLocalSystemSize(); ++local_dof) { UInt equ_number = equation_number(local_dof); Vector<Int> exp_val; UInt global_dof = dof_manager.localToGlobalEquationNumber(local_dof); if (dof_manager.isLocalOrMasterDOF(equ_number) || dof_manager.isSlaveDOF(equ_number)) { exp_val = {0, 1}; exp_val += global_dof * 2; } else { exp_val = {-1, -1}; } Vector<Int> val = it_data[local_dof]; if (exp_val != val) { std::cerr << "Failed !" << prank << " DOF: " << global_dof << " - l" << local_dof << " value:" << val << " expected: " << exp_val << std::endl; exit(1); } } }; test_data(); if (prank == 0) { Array<Int> test_gathered(dof_manager.getSystemSize(), 2); dof_synchronizer.gather(local_data_array, test_gathered); local_data_array.set(-1); dof_synchronizer.scatter(local_data_array, test_gathered); } else { dof_synchronizer.gather(local_data_array); local_data_array.set(-1); dof_synchronizer.scatter(local_data_array); } test_data(); finalize(); return 0; } diff --git a/test/test_synchronizer/test_dof_synchronizer_communication.cc b/test/test_synchronizer/test_dof_synchronizer_communication.cc index 295b2e1c9..dd6245ff9 100644 --- a/test/test_synchronizer/test_dof_synchronizer_communication.cc +++ b/test/test_synchronizer/test_dof_synchronizer_communication.cc @@ -1,102 +1,102 @@ /** * @file test_dof_synchronizer_communication.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Tue Dec 09 2014 * * @brief test to synchronize global equation numbers * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_synchronizer.hh" #include "dof_synchronizer.hh" #include "synchronizer_registry.hh" #include "mesh.hh" #include "mesh_partition_scotch.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" #endif //AKANTU_USE_IOHELPER #include "test_dof_data_accessor.hh" using namespace akantu; /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { initialize(argc, argv); UInt spatial_dimension = 3; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); bool wait=true; if(argc >1) { if(prank == 0) while(wait); } ElementSynchronizer * communicator = NULL; if(prank == 0) { mesh.read("cube.msh"); MeshPartition * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } /* -------------------------------------------------------------------------- */ /* test the communications of the dof synchronizer */ /* -------------------------------------------------------------------------- */ std::cout << "Initializing the synchronizer" << std::endl; DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); dof_synchronizer.initGlobalDOFEquationNumbers(); AKANTU_DEBUG_INFO("Creating TestDOFAccessor"); TestDOFAccessor test_dof_accessor(dof_synchronizer.getGlobalDOFEquationNumbers()); SynchronizerRegistry synch_registry(test_dof_accessor); synch_registry.registerSynchronizer(dof_synchronizer,_gst_test); AKANTU_DEBUG_INFO("Synchronizing tag"); synch_registry.synchronize(_gst_test); delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_synchronizer/test_facet_synchronizer.cc b/test/test_synchronizer/test_facet_synchronizer.cc index d3b2c8d36..ca7acdf31 100644 --- a/test/test_synchronizer/test_facet_synchronizer.cc +++ b/test/test_synchronizer/test_facet_synchronizer.cc @@ -1,100 +1,61 @@ /** * @file test_facet_synchronizer.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Facet synchronizer test * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ - -#include "test_data_accessor.hh" #include "facet_synchronizer.hh" #include "mesh_utils.hh" #include "synchronizer_registry.hh" +#include "test_data_accessor.hh" #include <iostream> - /* -------------------------------------------------------------------------- */ using namespace akantu; -int main(int argc, char *argv[]) { +int main(int argc, char * argv[]) { akantu::initialize(argc, argv); UInt spatial_dimension = 3; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - Int psize = comm.getNbProc(); + const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); - DistributedSynchronizer * dist = NULL; /// partition the mesh - if(prank == 0) { + if (prank == 0) { mesh.read("facet.msh"); - MeshPartition * partition = new MeshPartitionScotch(mesh, spatial_dimension); - partition->partitionate(psize); - dist = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); - delete partition; - } else { - dist = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } - /// create facets - Mesh mesh_facets(mesh.initMeshFacets("mesh_facets")); - MeshUtils::buildAllFacets(mesh, mesh_facets, 0, dist); - - /// compute barycenter for each facet - ElementTypeMapArray<Real> barycenters("barycenters", "", 0); - mesh_facets.initElementTypeMapArray(barycenters, - spatial_dimension, - spatial_dimension - 1); + mesh.distribute(); - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); ++gt) { - GhostType ghost_type = *gt; - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, - ghost_type); - Mesh::type_iterator last_type = mesh_facets.lastType(spatial_dimension - 1, - ghost_type); + auto & synchronizer = mesh.getElementSynchronizer(); - for(; it != last_type; ++it) { - UInt nb_element = mesh_facets.getNbElement(*it, ghost_type); - Array<Real> & barycenter = barycenters(*it, ghost_type); - barycenter.resize(nb_element); - - Array<Real>::iterator< Vector<Real> > bary_it - = barycenter.begin(spatial_dimension); - - for (UInt elem = 0; elem < nb_element; ++elem, ++bary_it) - mesh_facets.getBarycenter(elem, *it, bary_it->storage(), ghost_type); - } - } + /// create facets + Mesh & mesh_facets = mesh.initMeshFacets("mesh_facets"); /// setup facet communications - FacetSynchronizer * facet_synchronizer = - FacetSynchronizer::createFacetSynchronizer(*dist, mesh_facets); - - AKANTU_DEBUG_INFO("Creating TestAccessor"); - TestAccessor test_accessor(mesh, barycenters); - SynchronizerRegistry synch_registry(test_accessor); + auto & facet_synchronizer = mesh_facets.getElementSynchronizer(); - synch_registry.registerSynchronizer(*facet_synchronizer, _gst_test); + // AKANTU_DEBUG_INFO("Creating TestAccessor"); + // TestAccessor test_accessor(mesh); + // SynchronizerRegistry synch_registry(test_accessor); - /// synchronize facets and check results - AKANTU_DEBUG_INFO("Synchronizing tag"); - synch_registry.synchronize(_gst_test); + // synch_registry.registerSynchronizer(facet_synchronizer, _gst_test); - delete facet_synchronizer; - delete dist; - akantu::finalize(); + // /// synchronize facets and check results + // AKANTU_DEBUG_INFO("Synchronizing tag"); + // synch_registry.synchronize(_gst_test); - return EXIT_SUCCESS; + return 0; } diff --git a/test/test_synchronizer/test_grid_synchronizer.cc b/test/test_synchronizer/test_grid_synchronizer.cc index 71b601229..90e97ddcc 100644 --- a/test/test_synchronizer/test_grid_synchronizer.cc +++ b/test/test_synchronizer/test_grid_synchronizer.cc @@ -1,299 +1,299 @@ /** * @file test_grid_synchronizer.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 01 2010 * @date last modification: Fri Feb 27 2015 * * @brief test the GridSynchronizer object * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_grid_dynamic.hh" #include "mesh.hh" #include "grid_synchronizer.hh" #include "mesh_partition.hh" #include "synchronizer_registry.hh" #include "test_data_accessor.hh" #ifdef AKANTU_USE_IOHELPER # include "io_helper.hh" #endif //AKANTU_USE_IOHELPER using namespace akantu; const UInt spatial_dimension = 2; typedef std::map<std::pair<Element, Element>, Real> pair_list; #include "test_grid_tools.hh" static void updatePairList(const ElementTypeMapArray<Real> & barycenter, const SpatialGrid<Element> & grid, Real radius, pair_list & neighbors, neighbors_map_t<spatial_dimension>::type & neighbors_map) { AKANTU_DEBUG_IN(); GhostType ghost_type = _not_ghost; Element e; e.ghost_type = ghost_type; // generate the pair of neighbor depending of the cell_list ElementTypeMapArray<Real>::type_iterator it = barycenter.firstType(_all_dimensions, ghost_type); ElementTypeMapArray<Real>::type_iterator last_type = barycenter.lastType(0, ghost_type); for(; it != last_type; ++it) { // loop over quad points e.type = *it; e.element = 0; const Array<Real> & barycenter_vect = barycenter(*it, ghost_type); UInt sp = barycenter_vect.getNbComponent(); Array<Real>::const_iterator< Vector<Real> > bary = barycenter_vect.begin(sp); Array<Real>::const_iterator< Vector<Real> > bary_end = barycenter_vect.end(sp); for(;bary != bary_end; ++bary, e.element++) { #if !defined(AKANTU_NDEBUG) Point<spatial_dimension> pt1(*bary); #endif SpatialGrid<Element>::CellID cell_id = grid.getCellID(*bary); SpatialGrid<Element>::neighbor_cells_iterator first_neigh_cell = grid.beginNeighborCells(cell_id); SpatialGrid<Element>::neighbor_cells_iterator last_neigh_cell = grid.endNeighborCells(cell_id); // loop over neighbors cells of the one containing the current element for (; first_neigh_cell != last_neigh_cell; ++first_neigh_cell) { SpatialGrid<Element>::Cell::const_iterator first_neigh_el = grid.beginCell(*first_neigh_cell); SpatialGrid<Element>::Cell::const_iterator last_neigh_el = grid.endCell(*first_neigh_cell); // loop over the quadrature point in the current cell of the cell list for (;first_neigh_el != last_neigh_el; ++first_neigh_el){ const Element & elem = *first_neigh_el; Array<Real>::const_iterator< Vector<Real> > neigh_it = barycenter(elem.type, elem.ghost_type).begin(sp); const Vector<Real> & neigh_bary = neigh_it[elem.element]; Real distance = bary->distance(neigh_bary); if(distance <= radius) { #if !defined(AKANTU_NDEBUG) Point<spatial_dimension> pt2(neigh_bary); neighbors_map[pt1].push_back(pt2); #endif std::pair<Element, Element> pair = std::make_pair(e, elem); pair_list::iterator p = neighbors.find(pair); if(p != neighbors.end()) { AKANTU_DEBUG_ERROR("Pair already registered [" << e << " " << elem << "] -> " << p->second << " " << distance); } else { neighbors[pair] = distance; } } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { akantu::initialize(argc, argv); Real radius = 0.001; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); ElementSynchronizer * dist = NULL; if(prank == 0) { mesh.read("bar.msh"); MeshPartition * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); dist = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { dist = ElementSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } mesh.computeBoundingBox(); const Vector<Real> & lower_bounds = mesh.getLowerBounds(); const Vector<Real> & upper_bounds = mesh.getUpperBounds(); Vector<Real> center = 0.5 * (upper_bounds + lower_bounds); Vector<Real> spacing(spatial_dimension); for (UInt i = 0; i < spatial_dimension; ++i) { spacing[i] = radius * 1.2; } SpatialGrid<Element> grid(spatial_dimension, spacing, center); 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); ElementTypeMapArray<Real> barycenters("", ""); mesh.initElementTypeMapArray(barycenters, spatial_dimension, spatial_dimension); Element e; e.ghost_type = ghost_type; for(; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); e.type = *it; Array<Real> & barycenter = barycenters(*it, ghost_type); barycenter.resize(nb_element); Array<Real>::iterator< Vector<Real> > bary_it = barycenter.begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem) { mesh.getBarycenter(elem, *it, bary_it->storage(), ghost_type); e.element = elem; grid.insert(e, *bary_it); ++bary_it; } } std::stringstream sstr; sstr << "mesh_" << prank << ".msh"; mesh.write(sstr.str()); Mesh grid_mesh(spatial_dimension, "grid_mesh", 0); std::stringstream sstr_grid; sstr_grid << "grid_mesh_" << prank << ".msh"; grid.saveAsMesh(grid_mesh); grid_mesh.write(sstr_grid.str()); std::cout << "Pouet 1" << std::endl; AKANTU_DEBUG_INFO("Creating TestAccessor"); TestAccessor test_accessor(mesh, barycenters); SynchronizerRegistry synch_registry(test_accessor); GridSynchronizer * grid_communicator = GridSynchronizer::createGridSynchronizer(mesh, grid); std::cout << "Pouet 2" << std::endl; ghost_type = _ghost; it = mesh.firstType(spatial_dimension, ghost_type); last_type = mesh.lastType(spatial_dimension, ghost_type); e.ghost_type = ghost_type; for(; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); e.type = *it; Array<Real> & barycenter = barycenters(*it, ghost_type); barycenter.resize(nb_element); Array<Real>::iterator< Vector<Real> > bary_it = barycenter.begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem) { mesh.getBarycenter(elem, *it, bary_it->storage(), ghost_type); e.element = elem; grid.insert(e, *bary_it); ++bary_it; } } Mesh grid_mesh_ghost(spatial_dimension, "grid_mesh_ghost", 0); std::stringstream sstr_gridg; sstr_gridg << "grid_mesh_ghost_" << prank << ".msh"; grid.saveAsMesh(grid_mesh_ghost); grid_mesh_ghost.write(sstr_gridg.str()); std::cout << "Pouet 3" << std::endl; neighbors_map_t<spatial_dimension>::type neighbors_map; pair_list neighbors; updatePairList(barycenters, grid, radius, neighbors, neighbors_map); pair_list::iterator nit = neighbors.begin(); pair_list::iterator nend = neighbors.end(); std::stringstream sstrp; sstrp << "pairs_" << prank; std::ofstream fout(sstrp.str().c_str()); for(;nit != nend; ++nit) { fout << "[" << nit->first.first << "," << nit->first.second << "] -> " << nit->second << std::endl; } std::string file = "neighbors_ref"; std::stringstream sstrf; sstrf << file << "_" << psize << "_" << prank; file = sstrf.str(); std::ofstream nout; nout.open(file.c_str()); neighbors_map_t<spatial_dimension>::type::iterator it_n = neighbors_map.begin(); neighbors_map_t<spatial_dimension>::type::iterator end_n = neighbors_map.end(); for(;it_n != end_n; ++it_n) { std::sort(it_n->second.begin(), it_n->second.end()); std::vector< Point<spatial_dimension> >::iterator it_v = it_n->second.begin(); std::vector< Point<spatial_dimension> >::iterator end_v = it_n->second.end(); nout << "####" << std::endl; nout << it_n->second.size() << std::endl; nout << it_n->first << std::endl; nout << "#" << std::endl; for(;it_v != end_v; ++it_v) { nout << *it_v << std::endl; } } fout.close(); synch_registry.registerSynchronizer(*dist, _gst_smm_mass); synch_registry.registerSynchronizer(*grid_communicator, _gst_test); AKANTU_DEBUG_INFO("Synchronizing tag on Dist"); synch_registry.synchronize(_gst_smm_mass); AKANTU_DEBUG_INFO("Synchronizing tag on Grid"); synch_registry.synchronize(_gst_test); delete grid_communicator; delete dist; akantu::finalize(); return EXIT_SUCCESS; } diff --git a/test/test_synchronizer/test_grid_synchronizer_check_neighbors.cc b/test/test_synchronizer/test_grid_synchronizer_check_neighbors.cc index a9ee15a17..e5b3eeff6 100644 --- a/test/test_synchronizer/test_grid_synchronizer_check_neighbors.cc +++ b/test/test_synchronizer/test_grid_synchronizer_check_neighbors.cc @@ -1,122 +1,122 @@ /** * @file test_grid_synchronizer_check_neighbors.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Mar 11 2013 * @date last modification: Fri Feb 27 2015 * * @brief Test the generation of neighbors list based on a akaentu::Grid * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ #include <fstream> #include <iostream> #include <string> #include "aka_common.hh" -#include "static_communicator.hh" +#include "communicator.hh" using namespace akantu; const UInt spatial_dimension = 3; #include "test_grid_tools.hh" void readNeighbors(std::ifstream & nin, neighbors_map_t<spatial_dimension>::type & neighbors_map_read) { std::string line; while (std::getline(nin, line)) { std::getline(nin, line); std::istringstream iss(line); UInt nb_neig; iss >> nb_neig; std::getline(nin, line); Point<spatial_dimension> pt; pt.read(line); std::getline(nin, line); for (UInt i = 0; i < nb_neig; ++i) { std::getline(nin, line); Point<spatial_dimension> ne; ne.read(line); neighbors_map_read[pt].push_back(ne); } } } int main(int argc, char *argv[]) { initialize(argc, argv); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); std::string file_ref = "neighbors_ref_1_0"; std::string file = "neighbors_ref"; std::stringstream sstr; sstr << file << "_" << psize << "_" << prank; file = sstr.str(); std::ifstream nin; neighbors_map_t<spatial_dimension>::type neighbors_map_read; nin.open(file_ref.c_str()); readNeighbors(nin, neighbors_map_read); nin.close(); neighbors_map_t<spatial_dimension>::type neighbors_map; nin.open(file.c_str()); readNeighbors(nin, neighbors_map); nin.close(); neighbors_map_t<spatial_dimension>::type::iterator it_n = neighbors_map.begin(); neighbors_map_t<spatial_dimension>::type::iterator end_n = neighbors_map.end(); for(;it_n != end_n; ++it_n) { std::sort(it_n->second.begin(), it_n->second.end()); std::vector< Point<spatial_dimension> >::iterator it_v = it_n->second.begin(); std::vector< Point<spatial_dimension> >::iterator end_v = it_n->second.end(); neighbors_map_t<spatial_dimension>::type::iterator it_nr = neighbors_map_read.find(it_n->first); if(it_nr == neighbors_map_read.end()) AKANTU_DEBUG_ERROR("Argh what is this point that is not present in the ref file " << it_n->first); std::vector< Point<spatial_dimension> >::iterator it_vr = it_nr->second.begin(); std::vector< Point<spatial_dimension> >::iterator end_vr = it_nr->second.end(); for(;it_v != end_v && it_vr != end_vr; ++it_v, ++it_vr) { if(*it_vr != *it_v) AKANTU_DEBUG_ERROR("Neighbors does not match " << *it_v << " != " << *it_vr << " neighbor of " << it_n->first); } if(it_v == end_v && it_vr != end_vr) { AKANTU_DEBUG_ERROR("Some neighbors of " << it_n->first << " are missing!"); } if(it_v != end_v && it_vr == end_vr) AKANTU_DEBUG_ERROR("Some neighbors of " << it_n->first << " are in excess!"); } akantu::finalize(); return EXIT_SUCCESS; } diff --git a/test/test_synchronizer/test_node_synchronizer.cc b/test/test_synchronizer/test_node_synchronizer.cc index 94452ce1c..f0c4986fa 100644 --- a/test/test_synchronizer/test_node_synchronizer.cc +++ b/test/test_synchronizer/test_node_synchronizer.cc @@ -1,130 +1,130 @@ /** * @file test_node_synchronizer.cc * * @author Nicolas Richart * * @date creation Tue Apr 04 2017 * * @brief test the default node synchronizer present in the mesh * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "mesh.hh" #include "node_synchronizer.hh" -#include "static_communicator.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <limits> /* -------------------------------------------------------------------------- */ using namespace akantu; class DataAccessorTest : public DataAccessor<UInt> { public: explicit DataAccessorTest(Array<int> & data) : data(data) {} UInt getNbData(const Array<UInt> & nodes, const SynchronizationTag &) const { return nodes.size() * sizeof(int); } void packData(CommunicationBuffer & buffer, const Array<UInt> & nodes, const SynchronizationTag &) const { for (auto node : nodes) { buffer << data(node); } } void unpackData(CommunicationBuffer & buffer, const Array<UInt> & nodes, const SynchronizationTag &) { for (auto node : nodes) { buffer >> data(node); } } protected: Array<int> & data; }; int main(int argc, char * argv[]) { initialize(argc, argv); UInt spatial_dimension = 3; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); if (prank == 0) mesh.read("cube.msh"); mesh.distribute(); UInt nb_nodes = mesh.getNbNodes(); Array<int> node_data(nb_nodes); constexpr int max_int = std::numeric_limits<int>::max(); for (UInt n = 0; n < nb_nodes; ++n) { UInt gn = mesh.getNodeGlobalId(n); if (mesh.isMasterNode(n)) node_data(n) = gn; else if (mesh.isLocalNode(n)) node_data(n) = -gn; else if (mesh.isSlaveNode(n)) node_data(n) = max_int; else node_data(n) = -max_int; } DataAccessorTest data_accessor(node_data); auto & node_synchronizer = mesh.getNodeSynchronizer(); node_synchronizer.synchronize(data_accessor, _gst_test); for (UInt n = 0; n < nb_nodes; ++n) { int gn = mesh.getNodeGlobalId(n); if(!((mesh.isMasterNode(n) && node_data(n) == gn) || (mesh.isLocalNode(n) && node_data(n) == -gn) || (mesh.isSlaveNode(n) && node_data(n) == gn) || (mesh.isPureGhostNode(n) && node_data(n) == -max_int) ) ) { debug::setDebugLevel(dblTest); std::cout << "prank : " << prank << " (node " << gn << "[" << n << "]) - " << "( isMaster: " << mesh.isMasterNode(n) << " && " << node_data(n) << " == " << gn << ") " << "( isLocal: " << mesh.isLocalNode(n) << " && " << node_data(n) << " == " << - gn << ") " << "( isSlave: " << mesh.isSlaveNode(n) << " && " << node_data(n) << " == " << gn << ") " << "( isPureGhost: " << mesh.isPureGhostNode(n) << " && " << node_data(n) << " == " << -max_int << ") " << std::endl; debug::setDebugLevel(dblDebug); return -1; } } finalize(); return 0; } diff --git a/test/test_synchronizer/test_synchronizer_communication.cc b/test/test_synchronizer/test_synchronizer_communication.cc index 18aab7d4d..aab198caa 100644 --- a/test/test_synchronizer/test_synchronizer_communication.cc +++ b/test/test_synchronizer/test_synchronizer_communication.cc @@ -1,160 +1,160 @@ /** * @file test_synchronizer_communication.cc * * @author Dana Christen <dana.christen@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 01 2010 * @date last modification: Sun Oct 19 2014 * * @brief test to synchronize barycenters * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_random_generator.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_partition_scotch.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ //#define DUMP #if defined(AKANTU_USE_IOHELPER) && defined(DUMP) #include "dumper_paraview.hh" #endif // AKANTU_USE_IOHELPER #include "test_data_accessor.hh" using namespace akantu; /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { initialize(argc, argv); UInt spatial_dimension = 3; Mesh mesh(spatial_dimension); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); bool wait = true; if (argc > 1) { if (prank == 0) while (wait) ; } if (prank == 0) mesh.read("cube.msh"); mesh.distribute(); /// compute barycenter for each facet ElementTypeMapArray<Real> barycenters("barycenters", "", 0); barycenters.initialize(mesh, _nb_component = spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; 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); Array<Real> & barycenter = barycenters(*it, ghost_type); barycenter.resize(nb_element); Array<Real>::iterator<Vector<Real>> bary_it = barycenter.begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem, ++bary_it) mesh.getBarycenter(elem, *it, bary_it->storage(), ghost_type); } } AKANTU_DEBUG_INFO("Creating TestAccessor"); TestAccessor test_accessor(mesh, barycenters); SynchronizerRegistry synch_registry; synch_registry.registerDataAccessor(test_accessor); synch_registry.registerSynchronizer(mesh.getElementSynchronizer(), _gst_test); AKANTU_DEBUG_INFO("Synchronizing tag"); synch_registry.synchronize(_gst_test); // Checking the tags in MeshData (not a very good test because they're all // identical, // but still...) Mesh::type_iterator it = mesh.firstType(_all_dimensions); Mesh::type_iterator last_type = mesh.lastType(_all_dimensions); for (; it != last_type; ++it) { Array<UInt> & tags = mesh.getData<UInt>("tag_0", *it); Array<UInt>::const_vector_iterator tags_it = tags.begin(1); Array<UInt>::const_vector_iterator tags_end = tags.end(1); AKANTU_DEBUG_ASSERT( mesh.getNbElement(*it) == tags.size(), "The number of tags does not match the number of elements on rank " << prank << "."); std::cout << std::dec << " I am rank " << prank << " and here's my MeshData dump for types " << *it << " (it should contain " << mesh.getNbElement(*it) << " elements and it has " << tags.size() << "!) :" << std::endl; std::cout << std::hex; debug::setDebugLevel(dblTest); for (; tags_it != tags_end; ++tags_it) { std::cout << tags_it->operator()(0) << " "; } debug::setDebugLevel(dblInfo); std::cout << std::endl; } #if defined(AKANTU_USE_IOHELPER) && defined(DUMP) DumperParaview dumper("test-scotch-partition"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost); dumper.registerField("partitions", new DumperIOHelper::ElementPartitionField<>(mesh, spatial_dimension, _not_ghost)); dumper.dump(); DumperParaview dumper_ghost("test-scotch-partition-ghost"); dumper_ghost.registerMesh(mesh, spatial_dimension, _ghost); dumper_ghost.registerField("partitions", new DumperIOHelper::ElementPartitionField<>(mesh, spatial_dimension, _ghost)); dumper_ghost.dump(); #endif //AKANTU_USE_IOHELPER finalize(); return EXIT_SUCCESS; } diff --git a/third-party/iohelper/src/paraview_helper.tcc b/third-party/iohelper/src/paraview_helper.tcc index b016755c0..6afdb9259 100644 --- a/third-party/iohelper/src/paraview_helper.tcc +++ b/third-party/iohelper/src/paraview_helper.tcc @@ -1,308 +1,309 @@ #include <cassert> #if defined(__INTEL_COMPILER) #pragma warning ( push ) /// remark #981: operands are evaluated in unspecified order #pragma warning ( disable : 981 ) #endif //defined(__INTEL_COMPILER) inline std::string ParaviewHelper::dataTypeToStr(DataType data_type) { std::string str; switch(data_type) { case _bool : str = "UInt8" ; break; case _uint : str = "UInt32" ; break; case _int : str = "Int32" ; break; case _float : str = "Float32"; break; case _double : str = "Float64"; break; case _uint64 : str = "UInt64" ; break; case _int64 : str = "Int64" ; break; } return str; } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::visitField(T & visited){ this->position_flag = false; switch (current_stage){ case _s_writeFieldProperty: writeFieldProperty(visited); break; - case _s_writePosition: this->position_flag = true; + case _s_writePosition: this->position_flag = true; /* FALLTHRU */ + // [[fallthrough]] un-comment when compiler gets it case _s_writeField: writeField(visited); break; case _s_writeConnectivity: writeConnectivity(visited); break; case _s_writeElemType: writeElemType(visited); break; case _s_buildOffsets: writeOffsets(visited); break; default: std::stringstream sstr; sstr << "the stage " << current_stage << " is not a known paraviewhelper stage"; IOHELPER_THROW(sstr.str(), IOHelperException::_et_unknown_visitor_stage); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::writeFieldProperty(T & data){ if (data.isHomogeneous() == false) IOHELPER_THROW(std::string("try to write field property of a non homogeneous field"), IOHelperException::_et_non_homogeneous_data); UInt dim = data.getDim(); std::string name = data.getName(); PDataArray(name, dim, dataTypeToStr(data.getDataType())); } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::writeField(T & data){ typename T::iterator it = data.begin(); typename T::iterator end = data.end(); compteur = 0; UInt dim; if(data.isHomogeneous()) { dim = data.getDim(); if(position_flag) dim = 3; for (; it != end; ++it) pushData((*it), dim); } else { for (; it != end; ++it) pushData((*it)); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::writeConnectivity(T & data) { typename T::iterator it = data.begin(); typename T::iterator end = data.end(); for (; it != end; ++it) { ElemType type = (ElemType) it.element_type(); //typename T::iterator::type & n = *it; UInt dim = (*it).size(); assert(nb_node_per_elem[type] == dim); UInt * reorder = this->write_reorder[type]; for (UInt i = 0; i < dim; ++i) { this->pushDatum((*it)[reorder[i]], dim); } } } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::writeElemType(T & data){ typename T::iterator it = data.begin(); typename T::iterator end = data.end(); for (; it != end; ++it) { ElemType type = (ElemType) it.element_type(); this->pushDatum(this->paraview_code_type[type], 1); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::writeOffsets(T & data){ typename T::iterator it = data.begin(); typename T::iterator end = data.end(); UInt count = 0; for (; it != end; ++it) { count += (*it).size(); pushDatum(count); } } /* -------------------------------------------------------------------------- */ template <template<typename T> class Cont, typename T> inline void ParaviewHelper::pushData(const Cont<T> & n, UInt dim){ for (UInt i = 0; i < n.size(); ++i) { pushDatum<T>(n[i], dim); } for (UInt i = n.size(); i < dim; ++i) { T t = T(); this->pushDatum<T>(t, dim); } } /* -------------------------------------------------------------------------- */ template <template<typename T> class Cont, typename T> inline void ParaviewHelper::pushData(const Cont<T> & n) { for (UInt i = 0; i < n.size(); ++i) { pushDatum<T>(n[i], n.size()); } } /* -------------------------------------------------------------------------- */ inline void ParaviewHelper::setMode(int mode){ bflag = BASE64 & mode; } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::writePVTU(T & per_node_data, T & per_elem_data, const std::vector<std::string> & vtus){ current_stage = _s_writeFieldProperty; file << "<VTKFile type=\"PUnstructuredGrid\" version=\"0.1\" " << std::endl; file << "byte_order=\"LittleEndian\">" << std::endl; file << " <PUnstructuredGrid GhostLevel=\"0\">" << std::endl; file << " <PPoints>" << std::endl; file << " <PDataArray type=\"Float64\" NumberOfComponents=\"3\" format=\""; if (bflag == BASE64) file << "binary"; else file << "ascii"; file << "\" />" << std::endl; file << " </PPoints>" << std::endl; file << " <PPointData>" << std::endl; typename T::iterator itNodeField = per_node_data.begin(); typename T::iterator endNodeField = per_node_data.end(); for ( ; itNodeField != endNodeField ; ++itNodeField) if ((*itNodeField).first != "positions") (*itNodeField).second->accept(*this); file << " </PPointData>" << std::endl; file << " <PCellData>" << std::endl; typename T::iterator itElemField = per_elem_data.begin(); typename T::iterator endElemField = per_elem_data.end(); for (; itElemField != endElemField ; ++itElemField) { std::string name = (*itElemField).first; if (name == "connectivities" || name == "element_type") continue; (*itElemField).second->accept(*this); } file << " </PCellData>" << std::endl; for (UInt l = 0 ; l < vtus.size() ; ++l) file << " <Piece Source=\"" << vtus[l] << "\" />" << std::endl; file << " </PUnstructuredGrid>" << std::endl; file << "</VTKFile>" << std::endl; file.close(); } /* -------------------------------------------------------------------------- */ template <typename T> void ParaviewHelper::pushDataFields(T & per_node_data, T & per_elem_data){ startPointDataList(); { typename T::iterator itNodeField = per_node_data.begin(); typename T::iterator endNodeField = per_node_data.end(); for ( ; itNodeField != endNodeField ; ++itNodeField) { std::string name = (*itNodeField).first; if (name == "positions") continue; FieldInterface & f = *(*itNodeField).second; startData(f.getName(), f.getDim(), dataTypeToStr(f.getDataType())); pushField(f); endData(); } } endPointDataList(); startCellDataList(); { typename T::iterator itElemField = per_elem_data.begin(); typename T::iterator endElemField = per_elem_data.end(); for ( ; itElemField != endElemField ; ++itElemField) { std::string name = (*itElemField).first; if (name == "connectivities" || name == "element_type") continue; FieldInterface & f = *(*itElemField).second; startData(f.getName(),f.getDim(), dataTypeToStr(f.getDataType())); pushField(f); endData(); } } endCellDataList(); } /* -------------------------------------------------------------------------- */ template <typename T> inline void ParaviewHelper::pushDatum(const T & n, __attribute__((unused)) UInt size){ if (bflag == BASE64) b64.push<T>(n); else{ if (compteur == 0) file << " "; ++compteur; file << n << " "; } } /* -------------------------------------------------------------------------- */ template <> inline void ParaviewHelper::pushDatum<double>(const double & n, UInt size){ if (bflag == BASE64) b64.push<double>(n); else { if (compteur % size == 0) file << " "; file << std::setw(22); file << std::setprecision(15); file << std::scientific; file << n; file << " "; ++compteur; if (compteur % size == 0) file << std::endl; } } /* -------------------------------------------------------------------------- */ template <> inline void ParaviewHelper::pushDatum<ElemType>(const ElemType & type, __attribute__((unused)) UInt size){ UInt n = this->paraview_code_type[type]; pushDatum<UInt>(n); } /* -------------------------------------------------------------------------- */ inline void ParaviewHelper::pushPosition(FieldInterface & f){ current_stage = _s_writePosition; f.accept(*this); } /* -------------------------------------------------------------------------- */ inline void ParaviewHelper::pushField(FieldInterface & f){ current_stage = _s_writeField; f.accept(*this); } /* -------------------------------------------------------------------------- */ inline void ParaviewHelper::pushConnectivity(FieldInterface & f) { current_stage = _s_writeConnectivity; f.accept(*this); } /* -------------------------------------------------------------------------- */ inline void ParaviewHelper::pushElemType(FieldInterface & f) { current_stage = _s_writeElemType; f.accept(*this); } /* -------------------------------------------------------------------------- */ inline void ParaviewHelper::buildOffsets(FieldInterface & f){ current_stage = _s_buildOffsets; f.accept(*this); } /* -------------------------------------------------------------------------- */ #if defined(__INTEL_COMPILER) #pragma warning ( pop ) #endif //defined(__INTEL_COMPILER)