diff --git a/src/common/aka_grid_tmpl.hh b/src/common/aka_grid_tmpl.hh index 1bcad788d..3c815bbb4 100644 --- a/src/common/aka_grid_tmpl.hh +++ b/src/common/aka_grid_tmpl.hh @@ -1,396 +1,396 @@ /** * @file aka_grid_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Jul 28 15:27:55 2011 * * @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/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template<typename T> RegularGrid<T>::RegularGrid(UInt dimension, Real * lower_bounds, Real * upper_bounds, Real * spacing) : dimension(dimension) { // UInt total_nb_cells = 1; total_nb_cells = 1; this->dimension = dimension; std::fill_n(this->upper_bounds, 3, 0); std::fill_n(this->lower_bounds, 3, 0); std::fill_n(this->spacing, 3, 0); std::fill_n(this->nb_cells, 3, 0); for (UInt i = 0; i < dimension; ++i) { // +2 to add an extra cell on each side this->nb_cells[i] = UInt(std::ceil((upper_bounds[i] - lower_bounds[i]) / spacing[i]) + 2); this->lower_bounds[i] = lower_bounds[i] - spacing[i]; this->upper_bounds[i] = this->lower_bounds[i] + this->nb_cells[i] * spacing[i]; this->spacing[i] = spacing[i]; total_nb_cells *= this->nb_cells[i]; } this->data.resize(total_nb_cells); } /* -------------------------------------------------------------------------- */ template<typename T> class RegularGrid<T>::Cell { public: Cell() { id = 0; position[0] = position[1] = position[2] = 0; grid = NULL; } Cell(const RegularGrid<T> & grid) : grid(&grid) { id = 0; std::fill_n(position, 3, 0); } Cell(const Cell & cell) { if(&cell != this) { id = cell.id; position[0] = cell.position[0]; position[1] = cell.position[1]; position[2] = cell.position[2]; grid = cell.grid; } } Cell & operator=(const Cell & cell) { if(&cell != this) { id = cell.id; position[0] = cell.position[0]; position[1] = cell.position[1]; position[2] = cell.position[2]; grid = cell.grid; } return *this; } bool operator==(const Cell & cell) const { return id == cell.id; } bool operator!=(const Cell & cell) const { return id != cell.id; } inline void updateID() { id = 0; for (UInt i = grid->getDimension() - 1; i > 0; --i) { id += position[i]; id *= grid->getNbCells(i - 1); } id += position[0]; } friend class RegularGrid<T>; friend class GridSynchronizer; private: const RegularGrid<T> * grid; UInt id; UInt position[3]; }; /* -------------------------------------------------------------------------- */ template<typename T> inline typename RegularGrid<T>::iterator RegularGrid<T>::beginCell(const typename RegularGrid<T>::Cell & cell) { return data(cell.id).begin(); } /* -------------------------------------------------------------------------- */ template<typename T> inline typename RegularGrid<T>::iterator RegularGrid<T>::endCell(const typename RegularGrid<T>::Cell cell) { return data(cell.id).end(); } /* -------------------------------------------------------------------------- */ template<typename T> inline typename RegularGrid<T>::const_iterator RegularGrid<T>::beginCell(const typename RegularGrid<T>::Cell & cell) const { return data(cell.id).begin(); } /* -------------------------------------------------------------------------- */ template<typename T> inline typename RegularGrid<T>::const_iterator RegularGrid<T>::endCell(const typename RegularGrid<T>::Cell & cell) const { return data(cell.id).end(); } /* -------------------------------------------------------------------------- */ template<typename T> void RegularGrid<T>::insert(const T & d, const types::RVector & position) { UInt num_cell = getCell(position).id; AKANTU_DEBUG_ASSERT(num_cell < total_nb_cells, "The position is not in the grid (" << num_cell << " > " << total_nb_cells << ") : " << position); data(num_cell).push_back(d); } // /* -------------------------------------------------------------------------- */ // template<typename T> // void RegularGrid<T>::count(const types::RVector & position) { // Cell cell = getCell(position); // UInt num_cell = cell.id; // // std::cout << num_cell << " - " // // << cell.position[0] << ", " << cell.position[1] << ", " << cell.position[2] << " : " // // << position[0] << ", " << position[1] << ", " << position[2] // // << std::endl; // data.rowOffset(num_cell)++; // } /* -------------------------------------------------------------------------- */ template<typename T> inline typename RegularGrid<T>::Cell RegularGrid<T>::getCell(const types::RVector & position) const { Cell cell(*this); for (UInt i = 0; i < dimension; ++i) { cell.position[i] = getCell(position(i), i); } cell.updateID(); return cell; } /* -------------------------------------------------------------------------- */ template<typename T> inline UInt RegularGrid<T>::getCell(Real position, UInt direction) const { return UInt(std::floor((position - lower_bounds[direction]) / spacing[direction])); } /* -------------------------------------------------------------------------- */ template<typename T> struct RegularGrid<T>::neighbor_cells_iterator : private std::iterator<std::forward_iterator_tag, UInt> { neighbor_cells_iterator(const RegularGrid & grid, const Cell & cell, bool end) : cell(cell), grid(grid) { std::fill_n(position_start, 3, -1); std::fill_n(position_end , 3, 1); for (UInt i = 0; i < 3; ++i) { if((grid.getNbCells(i) == 0) || // no cells in this direction (cell.position[i] == 0)) // first cell in this direction position_start[i] = 0; if((grid.getNbCells(i) == 0) || // no cells in this direction (cell.position[i] == grid.getNbCells(i) - 1)) // last cell in this direction position_end[i] = 0; position[i] = end ? position_end[i] : position_start[i]; } updateIt(); if(end) { (this->it)++; } }; neighbor_cells_iterator(const neighbor_cells_iterator & it) : cell(it.cell), it(it.it), grid(it.grid) { std::copy(it.position , it.position + 3, position ); std::copy(it.position_start, it.position_start + 3, position_start); std::copy(it.position_end , it.position_end + 3, position_end ); }; neighbor_cells_iterator& operator++() { bool last = false; if(position[0] < position_end[0]) { position[0]++; } else { position[0] = position_start[0]; if(position[1] < position_end[1]) { position[1]++; } else { position[1] = position_start[1]; if(position[2] < position_end[2]) { position[2]++; } else { last = true; } } } if(last) ++it; else { updateIt(); } return *this; }; neighbor_cells_iterator operator++(int) { neighbor_cells_iterator tmp(*this); operator++(); return tmp; }; bool operator==(const neighbor_cells_iterator& rhs) { return cell == rhs.cell && it = rhs.it; }; bool operator!=(const neighbor_cells_iterator& rhs) { return cell != rhs.cell || it != rhs.it; }; Cell operator*() { Cell cur_cell(grid); for (UInt i = 0; i < 3; ++i) cur_cell.position[i] = cell.position[i] + position[i]; cur_cell.updateID(); return cur_cell; }; private: void updateIt() { it = 0; for (UInt i = 0; i < 3; ++i) it = it * 3 + (position[i] + 1); } private: // UInt cur_cell; //current position of the iterator const Cell & cell; //central cell UInt it; // number representing the current neighbor in base 3; Int position_start[3], position_end[3], position[3]; const RegularGrid & grid; }; /* -------------------------------------------------------------------------- */ template<typename T> inline typename RegularGrid<T>::neighbor_cells_iterator RegularGrid<T>::beginNeighborCells(const typename RegularGrid<T>::Cell & cell) { return neighbor_cells_iterator(*this, cell, false); } template<typename T> inline typename RegularGrid<T>::neighbor_cells_iterator RegularGrid<T>::endNeighborCells(const typename RegularGrid<T>::Cell & cell) { return neighbor_cells_iterator(*this, cell, true); } /* -------------------------------------------------------------------------- */ template<typename T> void RegularGrid<T>::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "RegularGrid<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; stream << space << " + dimension : " << this->dimension << std::endl; stream << space << " + lower_bounds : {" << this->lower_bounds[0] << ", " << this->lower_bounds[1] << ", " << this->lower_bounds[2] << "}" << std::endl; stream << space << " + upper_bounds : {" << this->upper_bounds[0] << ", " << this->upper_bounds[1] << ", " << this->upper_bounds[2] << "}" << std::endl; stream << space << " + spacing : {" << this->spacing[0] << ", " << this->spacing[1] << ", " << this->spacing[2] << "}" << std::endl; stream << space << " + nb_cells : " << this->total_nb_cells << " - {" << this->nb_cells[0] << ", " << this->nb_cells[1] << ", " << this->nb_cells[2] << "}" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ #include "mesh.hh" __BEGIN_AKANTU__ template<typename T> void RegularGrid<T>::saveAsMesh(Mesh & mesh) const { Vector<Real> & nodes = const_cast<Vector<Real> &>(mesh.getNodes()); UInt nb_nodes = 1; for (UInt i = 0; i < dimension; ++i) { nb_nodes *= (nb_cells[i] + 1); } nodes.resize(nb_nodes); if(dimension == 1) { for (UInt n = 0; n < nb_nodes; ++n) { - nodes.at(n, 0) = n * spacing[0] + lower_bounds[0]; + nodes(n, 0) = n * spacing[0] + lower_bounds[0]; } mesh.addConnectivityType(_segment_2); Vector<UInt> & connectivity = const_cast<Vector<UInt> &>(mesh.getConnectivity(_segment_2)); connectivity.resize(total_nb_cells); for (UInt e = 0; e < nb_cells[0]; ++e) { connectivity(e, 0) = e; connectivity(e, 1) = e + 1; } } if(dimension == 2) { UInt nnx = nb_cells[0] + 1; UInt nny = nb_cells[1] + 1; for (UInt nx = 0; nx < nnx; ++nx) { for (UInt ny = 0; ny < nny; ++ny) { UInt n = nx * nny + ny; nodes(n, 0) = nx * spacing[0] + lower_bounds[0]; nodes(n, 1) = ny * spacing[1] + lower_bounds[1]; } } mesh.addConnectivityType(_quadrangle_4); Vector<UInt> & connectivity = const_cast<Vector<UInt> &>(mesh.getConnectivity(_quadrangle_4)); connectivity.resize(total_nb_cells); for (UInt ex = 0; ex < nb_cells[0]; ++ex) { for (UInt ey = 0; ey < nb_cells[1]; ++ey) { UInt e = (ex * nb_cells[1] + ey); connectivity(e, 0) = ex * nny + ey; connectivity(e, 1) = (ex + 1) * nny + ey; connectivity(e, 2) = (ex + 1) * nny + ey + 1; connectivity(e, 3) = ex * nny + ey + 1; } } } if(dimension == 3) { UInt nnx = nb_cells[0] + 1; UInt nny = nb_cells[1] + 1; UInt nnz = nb_cells[2] + 1; for (UInt nx = 0; nx < nnx; ++nx) { for (UInt ny = 0; ny < nny; ++ny) { for (UInt nz = 0; nz < nnz; ++nz) { UInt n = (nx * nny + ny) * nnz + nz; nodes(n, 0) = nx * spacing[0] + lower_bounds[0]; nodes(n, 1) = ny * spacing[1] + lower_bounds[1]; nodes(n, 2) = nz * spacing[2] + lower_bounds[2]; } } } mesh.addConnectivityType(_hexahedron_8); Vector<UInt> & connectivity = const_cast<Vector<UInt> &>(mesh.getConnectivity(_hexahedron_8)); connectivity.resize(total_nb_cells); for (UInt ex = 0; ex < nb_cells[0]; ++ex) { for (UInt ey = 0; ey < nb_cells[1]; ++ey) { for (UInt ez = 0; ez < nb_cells[2]; ++ez) { UInt e = (ex * nb_cells[1] + ey) * nb_cells[2] + ez; connectivity(e, 0) = (ex * nny + ey ) * nnz + ez; connectivity(e, 1) = ((ex+1) * nny + ey ) * nnz + ez; connectivity(e, 2) = ((ex+1) * nny + ey+1) * nnz + ez; connectivity(e, 3) = (ex * nny + ey+1) * nnz + ez; connectivity(e, 4) = (ex * nny + ey ) * nnz + ez+1; connectivity(e, 5) = ((ex+1) * nny + ey ) * nnz + ez+1; connectivity(e, 6) = ((ex+1) * nny + ey+1) * nnz + ez+1; connectivity(e, 7) = (ex * nny + ey+1) * nnz + ez+1; } } } } } diff --git a/src/common/aka_vector.hh b/src/common/aka_vector.hh index aac3d72d9..9ab2ba20c 100644 --- a/src/common/aka_vector.hh +++ b/src/common/aka_vector.hh @@ -1,369 +1,364 @@ /** * @file aka_vector.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Jun 17 10:04:55 2010 * * @brief class of vectors * * @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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_VECTOR_HH__ #define __AKANTU_VECTOR_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <typeinfo> #include <vector> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class Matrix; /// class that afford to store vectors in static memory class VectorBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: VectorBase(const ID & id = ""); virtual ~VectorBase(); /* ------------------------------------------------------------------------ */ /* 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: AKANTU_GET_MACRO(AllocatedSize, allocated_size, UInt); AKANTU_GET_MACRO(Size, size, UInt); AKANTU_GET_MACRO(NbComponent, nb_component, UInt); AKANTU_GET_MACRO(ID, id, const ID &); AKANTU_GET_MACRO(Tag, tag, const std::string &); AKANTU_SET_MACRO(Tag, tag, const std::string &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the vector ID id; /// the size allocated UInt allocated_size; /// the size used UInt size; /// number of components UInt nb_component; /// size of the stored type UInt size_of_type; /// User defined tag std::string tag; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ namespace types { class Matrix; template<typename T> class Vector; } /* -------------------------------------------------------------------------- */ template<typename T, bool is_scal = is_scalar<T>::value > class Vector : public VectorBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef T value_type; typedef value_type & reference; typedef value_type * pointer_type; typedef const value_type & const_reference; /// Allocation of a new vector inline Vector(UInt size = 0, UInt nb_component = 1, const ID & id = ""); /// Allocation of a new vector with a default value Vector(UInt size, UInt nb_component, const value_type def_values[], const ID & id = ""); /// Allocation of a new vector with a default value Vector(UInt size, UInt nb_component, const_reference value, const ID & id = ""); /// Copy constructor (deep copy if deep=true) Vector(const Vector<value_type, is_scal>& vect, bool deep = true, const ID & id = ""); /// Copy constructor (deep copy) Vector(const std::vector<value_type> & vect); virtual inline ~Vector(); /* ------------------------------------------------------------------------ */ /* Iterator */ /* ------------------------------------------------------------------------ */ /// \todo protected: does not compile with intel check why public: template <class R, class IR = R, bool issame = is_same<IR, T>::value > class iterator_internal; public: /* ------------------------------------------------------------------------ */ // template<typename R, int fps = 0> class iterator : public iterator_internal<R> {}; // template<typename R, int fps = 0> class const_iterator : public iterator_internal<const R> {}; /* ------------------------------------------------------------------------ */ //template<class R> using iterator = iterator_internal<R>; template<typename R = T> class iterator : public iterator_internal<R> { public: typedef iterator_internal<R> parent; typedef typename parent::value_type value_type; typedef typename parent::pointer pointer; typedef typename parent::reference reference; typedef typename parent::difference_type difference_type; typedef typename parent::iterator_category iterator_category; public: iterator() : parent() {}; iterator(pointer_type data, UInt offset) : parent(data, offset) {}; iterator(pointer warped) : parent(warped) {}; iterator(const iterator & it) : parent(it) {}; iterator(const parent & it) : parent(it) {}; inline iterator operator+(difference_type n) { return parent::operator+(n);; } inline iterator operator-(difference_type n) { return parent::operator-(n);; } inline difference_type operator-(const iterator & b) { return parent::operator-(b); } inline iterator & operator++() { parent::operator++(); return *this; }; inline iterator & operator--() { parent::operator--(); return *this; }; inline iterator & operator+=(const UInt n) { parent::operator+=(n); return *this; } }; /* ------------------------------------------------------------------------ */ //template<class R> using const_iterator = iterator_internal<const R, R>; template<typename R = T> class const_iterator : public iterator_internal<const R, R> { public: typedef iterator_internal<const R, R> parent; typedef typename parent::value_type value_type; typedef typename parent::pointer pointer; typedef typename parent::reference reference; typedef typename parent::difference_type difference_type; typedef typename parent::iterator_category 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) {}; inline const_iterator operator+(difference_type n) { return parent::operator+(n); } inline const_iterator operator-(difference_type n) { return parent::operator-(n); } inline difference_type operator-(const const_iterator & b) { return parent::operator-(b); } inline const_iterator & operator++() { parent::operator++(); return *this; }; inline const_iterator & operator--() { parent::operator--(); return *this; }; inline const_iterator & operator+=(const UInt n) { parent::operator+=(n); return *this; } }; inline iterator<T> begin(); inline iterator<T> end(); inline const_iterator<T> begin() const; inline const_iterator<T> end() const; inline iterator< types::Vector<T> > begin(UInt n); inline iterator< types::Vector<T> > end(UInt n); inline const_iterator< types::Vector<T> > begin(UInt n) const; inline const_iterator< types::Vector<T> > end(UInt n) const; inline iterator< types::Matrix > begin(UInt m, UInt n); inline iterator< types::Matrix > end(UInt m, UInt n); inline const_iterator< types::Matrix > begin(UInt m, UInt n) const; inline const_iterator< types::Matrix > end(UInt m, UInt n) const; /// /!\ to use with caution inline iterator< types::Matrix > begin_reinterpret(UInt m, UInt n, UInt size, UInt nb_component); inline iterator< types::Matrix > end_reinterpret(UInt m, UInt n, UInt size, UInt nb_component); inline const_iterator< types::Matrix > begin_reinterpret(UInt m, UInt n, UInt size, UInt nb_component) const; inline const_iterator< types::Matrix > end_reinterpret(UInt m, UInt n, UInt size, UInt nb_component) const; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - /// get jth componemt of the ith tuple in read-only - inline const_reference get(UInt i, UInt j = 0) const; - /// get jth component of the ith tuple - inline reference at(UInt i, UInt j = 0); - /// add an element at the end of the vector with the value value for all /// component inline void push_back(const_reference value); /// add an element at the end of the vector inline void push_back(const value_type new_elem[]); template<typename Ret> inline void push_back(const iterator<Ret> & it); /** * remove an element and move the last one in the hole * /!\ change the order in the vector */ inline void erase(UInt i); template<typename R> inline void erase(const iterator<R> & it); /// change the size of the vector and allocate more memory if needed void resize(UInt size); /// change the number of components by interlacing data void extendComponentsInterlaced(UInt multiplicator, UInt stride); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; // Vector<T, is_scal>& operator=(const Vector<T, is_scal>& vect); /// search elem in the vector, return the position of the first occurrence or /// -1 if not found Int find(const_reference elem) const; Int find(T elem[]) const; /// set a vvector to 0 inline void clear() { std::fill_n(values, size*nb_component, T()); }; /// copy the content of an other vector void copy(const Vector<T, is_scal> & vect); /// give the address of the memory allocated for this vector T * storage() const { return values; }; protected: /// perform the allocation for the constructors void allocate(UInt size, UInt nb_component = 1); /// resize without initializing the memory void resizeUnitialized(UInt new_size); /* ------------------------------------------------------------------------ */ /* Operators */ /* ------------------------------------------------------------------------ */ public: Vector<T, is_scal> & operator-=(const Vector<T, is_scal> & vect); Vector<T, is_scal> & operator+=(const Vector<T, is_scal> & vect); Vector<T, is_scal> & operator*=(const T & alpha); inline reference operator()(UInt i, UInt j = 0); inline const_reference operator()(UInt i, UInt j = 0) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: UInt getSize() const{ return this->size; }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: /// array of values T * values; // /!\ very dangerous }; __END_AKANTU__ #include "aka_types.hh" __BEGIN_AKANTU__ #include "aka_vector_tmpl.hh" /* -------------------------------------------------------------------------- */ /* Inline Functions Vector<T, is_scal> */ /* -------------------------------------------------------------------------- */ template <typename T, bool is_scal> inline std::ostream & operator<<(std::ostream & stream, const Vector<T, is_scal> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ /* Inline Functions VectorBase */ /* -------------------------------------------------------------------------- */ inline std::ostream & operator<<(std::ostream & stream, const VectorBase & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_VECTOR_HH__ */ diff --git a/src/common/aka_vector_tmpl.hh b/src/common/aka_vector_tmpl.hh index a6d25cdb3..76947a0b9 100644 --- a/src/common/aka_vector_tmpl.hh +++ b/src/common/aka_vector_tmpl.hh @@ -1,902 +1,846 @@ /** * @file aka_vector_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Jul 15 00:09:33 2010 * * @brief Inline functions of the classes Vector<T> and VectorBase * * @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/>. * */ /* -------------------------------------------------------------------------- */ /* Inline Functions Vector<T> */ /* -------------------------------------------------------------------------- */ __END_AKANTU__ #include <memory> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline T & Vector<T, is_scal>::operator()(UInt i, UInt j) { AKANTU_DEBUG_ASSERT(size > 0, "The vector \"" << id << "\" is empty"); AKANTU_DEBUG_ASSERT((i < size) && (j < nb_component), "The value at position [" << i << "," << j << "] is out of range in vector \"" << id << "\""); return values[i*nb_component + j]; } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline const T & Vector<T, is_scal>::operator()(UInt i, UInt j) const { AKANTU_DEBUG_ASSERT(size > 0, "The vector \"" << id << "\" is empty"); AKANTU_DEBUG_ASSERT((i < size) && (j < nb_component), "The value at position [" << i << "," << j << "] is out of range in vector \"" << id << "\""); return values[i*nb_component + j]; } - -/* -------------------------------------------------------------------------- */ -template <class T, bool is_scal> -inline T & Vector<T, is_scal>::at(UInt i, UInt j) { - AKANTU_DEBUG_IN(); - AKANTU_DEBUG_ASSERT(size > 0, - "The vector is empty"); - AKANTU_DEBUG_ASSERT((i < size) && (j < nb_component), - "The value at position [" << i << "," << j - << "] is out of range"); - - AKANTU_DEBUG_OUT(); - return values[i*nb_component + j]; -} - -/* -------------------------------------------------------------------------- */ -template <class T, bool is_scal> -inline const T & Vector<T, is_scal>::get(UInt i, UInt j) const{ - AKANTU_DEBUG_IN(); - AKANTU_DEBUG_ASSERT(size > 0, - "The vector is empty"); - AKANTU_DEBUG_ASSERT((i < size) && (j < nb_component), - "The value at position [" << i << "," << j - << "] is out of range"); - - AKANTU_DEBUG_OUT(); - return values[i*nb_component + j]; -} - /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline void Vector<T, is_scal>::push_back(const T & value) { - // AKANTU_DEBUG_IN(); UInt pos = size; resizeUnitialized(size+1); - /// @todo see if with std::uninitialized_fill it allow to build vector of objects - std::uninitialized_fill_n(values + pos * nb_component, nb_component, value); - - // for (UInt i = 0; i < nb_component; ++i) { - // values[pos*nb_component + i] = value; - // } - - // AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline void Vector<T, is_scal>::push_back(const T new_elem[]) { - // AKANTU_DEBUG_IN(); UInt pos = size; resizeUnitialized(size+1); T * tmp = values + nb_component * pos; std::uninitialized_copy(new_elem, new_elem + nb_component, tmp); - - // for (UInt i = 0; i < nb_component; ++i) { - // values[pos*nb_component + i] = new_elem[i]; - // } - // AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template<class Ret> inline void Vector<T, is_scal>::push_back(const Vector<T, is_scal>::iterator<Ret> & it) { UInt pos = size; resizeUnitialized(size+1); T * tmp = values + nb_component * pos; T * new_elem = it.data(); std::uninitialized_copy(new_elem, new_elem + nb_component, tmp); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline void Vector<T, is_scal>::erase(UInt i){ AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT((size > 0), "The vector is empty"); AKANTU_DEBUG_ASSERT((i < size), - "The element at position [" << i << "] is out of range"); + "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(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal> & Vector<T, is_scal>::operator-=(const Vector<T, is_scal> & vect) { AKANTU_DEBUG_ASSERT((size == vect.size) && (nb_component == vect.nb_component), "The too vector don't have the same sizes"); T * a = values; T * b = vect.values; for (UInt i = 0; i < size*nb_component; ++i) { *a -= *b; ++a;++b; } return *this; } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal> & Vector<T, is_scal>::operator+=(const Vector<T, is_scal> & vect) { AKANTU_DEBUG_ASSERT((size == vect.size) && (nb_component == vect.nb_component), "The too vector don't have the same sizes"); T * a = values; T * b = vect.values; for (UInt i = 0; i < size*nb_component; ++i) { *a++ += *b++; } return *this; } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal> & Vector<T, is_scal>::operator*=(const T & alpha) { T * a = values; for (UInt i = 0; i < size*nb_component; ++i) { *a++ *= alpha; } return *this; } /* -------------------------------------------------------------------------- */ -/* Functions Vector<T, is_scal> */ +/* Functions Vector<T, is_scal> */ /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal>::Vector (UInt size, UInt nb_component, const ID & id) : VectorBase(id), values(NULL) { 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> Vector<T, is_scal>::Vector (UInt size, UInt nb_component, const T def_values[], const ID & id) : VectorBase(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); - // for (UInt j = 0; j < nb_component; ++j) { - // values[i*nb_component + j] = def_values[j]; - // } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal>::Vector (UInt size, UInt nb_component, const T & value, const ID & id) : VectorBase(id), values(NULL) { AKANTU_DEBUG_IN(); allocate(size, nb_component); std::uninitialized_fill_n(values, size*nb_component, value); - // for (UInt i = 0; i < nb_component*size; ++i) { - // values[i] = value; - // } - AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal>::Vector(const Vector<T, is_scal> & vect, bool deep, const ID & id) { AKANTU_DEBUG_IN(); this->id = (id == "") ? vect.id : id; if (deep) { allocate(vect.size, vect.nb_component); T * tmp = values; std::uninitialized_copy(vect.values, vect.values + size * nb_component, tmp); - // for (UInt i = 0; i < size; ++i) { - // for (UInt j = 0; j < nb_component; ++j) { - // values[i*nb_component + j] = vect.values[i*nb_component + j]; - // } - // } } else { this->values = vect.values; 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(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal>::Vector(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(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Vector<T, is_scal>::~Vector () { AKANTU_DEBUG_IN(); AKANTU_DEBUG(dblAccessory, "Freeing " << allocated_size*nb_component*sizeof(T) / 1024. << "kB (" << 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(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Vector<T, is_scal>::allocate(UInt size, UInt nb_component) { AKANTU_DEBUG_IN(); if (size == 0){ values = NULL; } else { values = static_cast<T*>(malloc(nb_component * size * sizeof(T))); AKANTU_DEBUG_ASSERT(values != NULL, "Cannot allocate " << nb_component * size * sizeof(T) / 1024. << "kB (" << id <<")"); } if (values == NULL) { this->size = this->allocated_size = 0; } else { AKANTU_DEBUG(dblAccessory, "Allocated " << size * nb_component * sizeof(T) / 1024. << "kB (" << 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 Vector<T, is_scal>::resize(UInt new_size) { UInt old_size = size; 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(); } } resizeUnitialized(new_size); T val = T(); if(size > old_size) std::uninitialized_fill(values + old_size*nb_component, values + size*nb_component, val); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Vector<T, is_scal>::resizeUnitialized(UInt new_size) { // AKANTU_DEBUG_IN(); // free some memory if(new_size <= allocated_size) { if(allocated_size - new_size > AKANTU_MIN_ALLOCATION) { AKANTU_DEBUG(dblAccessory, "Freeing " << (allocated_size - size)*nb_component*sizeof(T) / 1024. << "kB (" << id <<")"); // Normally there are no allocation problem when reducing an array T * tmp_ptr = static_cast<T*>(realloc(values, new_size * nb_component * sizeof(T))); if(new_size != 0 && tmp_ptr == NULL) { AKANTU_DEBUG_ERROR("Cannot free data (" << id << ")" << " [current allocated size : " << allocated_size << " | " << "requested size : " << new_size << "]"); } values = tmp_ptr; allocated_size = new_size; } size = new_size; // AKANTU_DEBUG_OUT(); return; } // allocate more memory UInt size_to_alloc = (new_size - allocated_size < AKANTU_MIN_ALLOCATION) ? allocated_size + AKANTU_MIN_ALLOCATION : new_size; T *tmp_ptr = static_cast<T*>(realloc(values, size_to_alloc * nb_component * sizeof(T))); AKANTU_DEBUG_ASSERT(tmp_ptr != NULL, "Cannot allocate " << size_to_alloc * nb_component * sizeof(T) / 1024. << "kB"); if (tmp_ptr == NULL) { AKANTU_DEBUG_ERROR("Cannot allocate more data (" << id << ")" << " [current allocated size : " << allocated_size << " | " << "requested size : " << new_size << "]"); } AKANTU_DEBUG(dblAccessory, "Allocating " << (size_to_alloc - allocated_size)*nb_component*sizeof(T) / 1024. << "kB"); allocated_size = size_to_alloc; size = new_size; values = tmp_ptr; // AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Vector<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(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Int Vector<T, is_scal>::find(const T & elem) const { AKANTU_DEBUG_IN(); UInt i = 0; for (; (i < size) && (values[i] != elem); ++i); AKANTU_DEBUG_OUT(); return (i == size) ? -1 : (Int) i; } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> Int Vector<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 -1; } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Vector<T, is_scal>::copy(const Vector<T, is_scal>& vect) { AKANTU_DEBUG_IN(); if(AKANTU_DEBUG_TEST(dblWarning)) if(vect.nb_component != nb_component) { AKANTU_DEBUG(dblWarning, "The two vectors do not have the same number of components"); } // this->id = vect.id; resize((vect.size * vect.nb_component) / nb_component); T * tmp = values; std::uninitialized_copy(vect.values, vect.values + size * nb_component, tmp); // memcpy(this->values, vect.values, vect.size * vect.nb_component * sizeof(T)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> void Vector<T, is_scal>::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); Real real_size = allocated_size * nb_component * size_of_type / 1024.0; std::streamsize prec = stream.precision(); std::ios_base::fmtflags ff = stream.flags(); stream.setf (std::ios_base::showbase); stream.precision(2); stream << space << "Vector<" << 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 : " << real_size << "kB" << 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); if(AKANTU_DEBUG_TEST(dblDump)) { stream << space << " + values : {"; for (UInt i = 0; i < this->size; ++i) { stream << "{"; for (UInt j = 0; j < this->nb_component; ++j) { stream << this->values[i*nb_component + j]; if(j != this->nb_component - 1) stream << ", "; } stream << "}"; if(i != this->size - 1) stream << ", "; } stream << "}" << std::endl; } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /* Inline Functions VectorBase */ /* -------------------------------------------------------------------------- */ inline UInt VectorBase::getMemorySize() const { return allocated_size * nb_component * size_of_type; } inline void VectorBase::empty() { size = 0; } /* -------------------------------------------------------------------------- */ /* Iterators */ /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template<class R, class IR, bool is_r_scal> class Vector<T, is_scal>::iterator_internal { public: typedef R value_type; typedef R* pointer; typedef R& reference; typedef IR internal_value_type; typedef IR* internal_pointer; typedef std::ptrdiff_t difference_type; typedef std::random_access_iterator_tag iterator_category; public: iterator_internal() : offset(0), initial(NULL), ret(NULL) {}; iterator_internal(pointer_type data, UInt offset) : offset(offset), initial(data), ret(new value_type(data)) { AKANTU_DEBUG_ASSERT(offset == ret->size(), "The iterator_internal is not compatible with the type " << typeid(value_type).name()); } iterator_internal(pointer warped) : offset(warped->size()), initial(warped->storage()), ret(const_cast<internal_pointer>(warped)) { } iterator_internal(const iterator_internal & it) { if(this != &it) { this->offset = it.offset; this->initial = it.initial; this->ret = new internal_value_type(*it.ret); } } virtual ~iterator_internal() { delete ret; }; inline iterator_internal & operator=(const iterator_internal & it) { if(this != &it) { this->offset = it.offset; this->initial = it.initial; if(this->ret) this->ret->shallowCopy(*it.ret); else this->ret = new internal_value_type(*it.ret); } return *this; } inline reference operator*() { return *ret; }; inline pointer operator->() { return ret; }; inline iterator_internal & operator++() { ret->values += offset; return *this; }; inline iterator_internal & operator--() { ret->values -= offset; return *this; }; inline iterator_internal & operator+=(const UInt n) { ret->values += offset * n; return *this; } inline iterator_internal & operator-=(const UInt n) { ret->values -= offset * n; return *this; } inline reference operator[](const UInt n) { ret->values = initial + n*offset; return *ret; } inline bool operator==(const iterator_internal & other) { return (*this).ret->values == other.ret->values; } inline bool operator!=(const iterator_internal & other) { return (*this).ret->values != other.ret->values; } inline bool operator <(const iterator_internal & other) { return (*this).ret->values < other.ret->values; } inline bool operator<=(const iterator_internal & other) { return (*this).ret->values <= other.ret->values; } inline bool operator> (const iterator_internal & other) { return (*this).ret->values > other.ret->values; } inline bool operator>=(const iterator_internal & other) { return (*this).ret->values >= other.ret->values; } inline iterator_internal operator+(difference_type n) { iterator_internal tmp(*this); tmp += n; return tmp; } inline iterator_internal operator-(difference_type n) { iterator_internal tmp(*this); tmp -= n; return tmp; } inline difference_type operator-(const iterator_internal & b) { return ret->values - b.ret->values; } inline pointer_type data() const { return ret->storage(); } protected: UInt offset; pointer_type initial; internal_pointer ret; }; /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::iterator< types::Vector<T> > Vector<T, is_scal>::begin(UInt n) { AKANTU_DEBUG_ASSERT(nb_component == n, "The iterator is not compatible with the type Vector(" << n<< ")"); return iterator< types::Vector<T> >(new types::Vector<T>(values, n)); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::iterator< types::Vector<T> > Vector<T, is_scal>::end(UInt n) { AKANTU_DEBUG_ASSERT(nb_component == n, "The iterator is not compatible with the type Vector(" << n<< ")"); return iterator< types::Vector<T> >(new types::Vector<T>(values + nb_component * size, n)); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::const_iterator< types::Vector<T> > Vector<T, is_scal>::begin(UInt n) const { AKANTU_DEBUG_ASSERT(nb_component == n, "The iterator is not compatible with the type Vector(" << n<< ")"); return const_iterator< types::Vector<T> >(new types::Vector<T>(values, n)); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::const_iterator< types::Vector<T> > Vector<T, is_scal>::end(UInt n) const { AKANTU_DEBUG_ASSERT(nb_component == n, "The iterator is not compatible with the type Vector(" << n<< ")"); return const_iterator< types::Vector<T> >(new types::Vector<T>(values + nb_component * size, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::iterator<types::Matrix> Vector<Real>::begin(UInt m, UInt n) { AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return iterator< types::Matrix >(new types::Matrix(values, m, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::iterator<types::Matrix> Vector<Real>::end(UInt m, UInt n) { AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return iterator<types::Matrix>(new types::Matrix(values + nb_component * size, m, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::const_iterator<types::Matrix> Vector<Real>::begin(UInt m, UInt n) const { AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return const_iterator< types::Matrix >(new types::Matrix(values, m, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::const_iterator<types::Matrix> Vector<Real>::end(UInt m, UInt n) const { AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return const_iterator<types::Matrix>(new types::Matrix(values + nb_component * size, m, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::iterator< types::Matrix > Vector<Real>::begin_reinterpret(UInt m, UInt n, __attribute__((unused)) UInt size, __attribute__((unused)) UInt nb_component) { AKANTU_DEBUG_ASSERT(nb_component * size == this->nb_component * this->size, "The new values for size (" << size << ") and nb_component (" << nb_component << ") are not compatible with the one of this vector"); AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return iterator< types::Matrix >(new types::Matrix(values + nb_component * 0, m, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::iterator< types::Matrix > Vector<Real>::end_reinterpret(UInt m, UInt n, UInt size, UInt nb_component) { AKANTU_DEBUG_ASSERT(nb_component * size == this->nb_component * this->size, "The new values for size (" << size << ") and nb_component (" << nb_component << ") are not compatible with the one of this vector"); AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return iterator<types::Matrix>(new types::Matrix(values + nb_component * size, m, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::const_iterator< types::Matrix > Vector<Real>::begin_reinterpret(UInt m, UInt n, __attribute__((unused)) UInt size, __attribute__((unused)) UInt nb_component) const { AKANTU_DEBUG_ASSERT(nb_component * size == this->nb_component * this->size, "The new values for size (" << size << ") and nb_component (" << nb_component << ") are not compatible with the one of this vector"); AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return const_iterator< types::Matrix >(new types::Matrix(values + nb_component * 0, m, n)); } /* -------------------------------------------------------------------------- */ template<> inline Vector<Real>::const_iterator< types::Matrix > Vector<Real>::end_reinterpret(UInt m, UInt n, UInt size, UInt nb_component) const { AKANTU_DEBUG_ASSERT(nb_component * size == this->nb_component * this->size, "The new values for size (" << size << ") and nb_component (" << nb_component << ") are not compatible with the one of this vector"); AKANTU_DEBUG_ASSERT(nb_component == n*m, "The iterator is not compatible with the type Matrix(" << m << "," << n<< ")"); return const_iterator<types::Matrix>(new types::Matrix(values + nb_component * size, m, n)); } /* -------------------------------------------------------------------------- */ /** * Specialization for scalar types */ template <class T, bool is_scal> template <class R, class IR> class Vector<T, is_scal>::iterator_internal<R, IR, true> { public: typedef R value_type; typedef R* pointer; typedef R& reference; typedef IR internal_value_type; typedef IR* internal_pointer; typedef std::ptrdiff_t difference_type; typedef std::random_access_iterator_tag iterator_category; public: iterator_internal(pointer data = NULL, __attribute__ ((unused)) UInt offset = 1) : ret(data), initial(data) { }; iterator_internal(const iterator_internal & it) { if(this != &it) { this->ret = it.ret; this->initial = it.initial; } } virtual ~iterator_internal() { }; inline iterator_internal & operator=(const iterator_internal & it) { if(this != &it) { this->ret = it.ret; this->initial = it.initial; } return *this; } inline reference operator*() { return *ret; }; inline pointer operator->() { return ret; }; inline iterator_internal & operator++() { ++ret; return *this; }; inline iterator_internal & operator--() { --ret; return *this; }; inline iterator_internal & operator+=(const UInt n) { ret += n; return *this; } inline iterator_internal & operator-=(const UInt n) { ret -= n; return *this; } inline reference operator[](const UInt n) { ret = initial + n; return *ret; } inline bool operator==(const iterator_internal & other) { return ret == other.ret; } inline bool operator!=(const iterator_internal & other) { return ret != other.ret; } inline bool operator< (const iterator_internal & other) { return ret < other.ret; } inline bool operator<=(const iterator_internal & other) { return ret <= other.ret; } inline bool operator> (const iterator_internal & other) { return ret > other.ret; } inline bool operator>=(const iterator_internal & other) { return ret >= other.ret; } inline iterator_internal operator-(difference_type n) { return iterator_internal(ret - n); } inline iterator_internal operator+(difference_type n) { return iterator_internal(ret + n); } inline difference_type operator-(const iterator_internal & b) { return ret - b.ret; } inline pointer data() const { return ret; } protected: pointer ret; pointer initial; }; /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> template<typename R> inline void Vector<T, is_scal>::erase(const iterator<R> & it) { T * curr = it.getCurrentStorage(); UInt pos = (curr - values) / nb_component; erase(pos); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::iterator<T> Vector<T, is_scal>::begin() { AKANTU_DEBUG_ASSERT(nb_component == 1, "this iterator cannot be used on a vector which has nb_component != 1"); return iterator<T>(values); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::iterator<T> Vector<T, is_scal>::end() { AKANTU_DEBUG_ASSERT(nb_component == 1, "this iterator cannot be used on a vector which has nb_component != 1"); return iterator<T>(values + size); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::const_iterator<T> Vector<T, is_scal>::begin() const { AKANTU_DEBUG_ASSERT(nb_component == 1, "this iterator cannot be used on a vector which has nb_component != 1"); return const_iterator<T>(values); } /* -------------------------------------------------------------------------- */ template <class T, bool is_scal> inline Vector<T, is_scal>::const_iterator<T> Vector<T, is_scal>::end() const { AKANTU_DEBUG_ASSERT(nb_component == 1, "this iterator cannot be used on a vector which has nb_component != 1"); return const_iterator<T>(values + size); } diff --git a/src/fem/by_element_type.hh b/src/fem/by_element_type.hh index 2f0f14bbb..430535cc5 100644 --- a/src/fem/by_element_type.hh +++ b/src/fem/by_element_type.hh @@ -1,182 +1,185 @@ /** * @file by_element_type.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Aug 4 14:40:34 2011 * * @brief storage class by element type * * @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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BY_ELEMENT_TYPE_HH__ #define __AKANTU_BY_ELEMENT_TYPE_HH__ #include "aka_common.hh" #include "aka_vector.hh" #include "aka_memory.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* ByElementType */ /* -------------------------------------------------------------------------- */ template<class Stored> class ByElementType { protected: typedef std::map<ElementType, Stored> DataMap; public: ByElementType(const ID & id = "by_element_type", const ID & parent_id = ""); ~ByElementType(); inline static std::string printType(const ElementType & type, const GhostType & ghost_type); inline bool exists(ElementType type, GhostType ghost_type = _not_ghost) const; inline const Stored & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; inline Stored & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost); inline Stored & operator()(const Stored & insert, const ElementType & type, const GhostType & ghost_type = _not_ghost); void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ class type_iterator : private std::iterator<std::forward_iterator_tag, const ElementType> { public: typedef const ElementType value_type; typedef const ElementType* pointer; typedef const ElementType& reference; protected: typedef typename ByElementType<Stored>::DataMap::const_iterator DataMapIterator; public: type_iterator(DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek); type_iterator(const type_iterator & it); inline reference operator*(); inline type_iterator & operator++(); type_iterator operator++(int); inline bool operator==(const type_iterator & other); inline bool operator!=(const type_iterator & other); private: DataMapIterator list_begin; DataMapIterator list_end; UInt dim; ElementKind kind; }; inline type_iterator firstType(UInt dim = 0, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; inline type_iterator lastType(UInt dim = 0, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; inline void setID(const ID & id) { this->id = id; } protected: inline DataMap & getData(GhostType ghost_type); inline const DataMap & getData(GhostType ghost_type) const; public: AKANTU_GET_MACRO(ID, id, ID); /* -------------------------------------------------------------------------- */ protected: ID id; DataMap data; DataMap ghost_data; }; /* -------------------------------------------------------------------------- */ /* Some typedefs */ /* -------------------------------------------------------------------------- */ template <typename T> class ByElementTypeVector : public ByElementType<Vector<T> *>, protected Memory { protected: typedef typename ByElementType<Vector<T> *>::DataMap DataMap; public: ByElementTypeVector() {}; // ByElementTypeVector(const ID & id = "by_element_type_vector", // const MemoryID & memory_id = 0) : // ByElementType<Vector<T> *>(id, memory_id) {}; ByElementTypeVector(const ID & id, const ID & parent_id, const MemoryID & memory_id = 0) : ByElementType<Vector<T> *>(id, parent_id), Memory(memory_id) {}; inline Vector<T> & alloc(UInt size, UInt nb_component, const ElementType & type, const GhostType & ghost_type); inline void alloc(UInt size, UInt nb_component, const ElementType & type); inline const Vector<T> & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; inline Vector<T> & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost); inline void setVector(const ElementType & type, const GhostType & ghost_type, const Vector<T> & vect); inline void free(); + + inline void onElementsRemoved(const ByElementTypeVector<UInt> & new_numbering); + }; /// to store data Vector<Real> by element type typedef ByElementTypeVector<Real> ByElementTypeReal; /// to store data Vector<Int> by element type typedef ByElementTypeVector<Int> ByElementTypeInt; /// to store data Vector<UInt> by element type typedef ByElementTypeVector<UInt> ByElementTypeUInt; /// Map of data of type UInt stored in a mesh typedef std::map<std::string, Vector<UInt> *> UIntDataMap; typedef ByElementType<UIntDataMap> ByElementTypeUIntDataMap; // /* -------------------------------------------------------------------------- */ // /* inline functions */ // /* -------------------------------------------------------------------------- */ // #if defined (AKANTU_INCLUDE_INLINE_IMPL) // # include "by_element_type_inline_impl.cc" // #endif __END_AKANTU__ #endif /* __AKANTU_BY_ELEMENT_TYPE_HH__ */ diff --git a/src/fem/by_element_type_tmpl.hh b/src/fem/by_element_type_tmpl.hh index c96c3b901..6423556f0 100644 --- a/src/fem/by_element_type_tmpl.hh +++ b/src/fem/by_element_type_tmpl.hh @@ -1,368 +1,399 @@ /** * @file by_element_type_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Aug 4 14:41:29 2011 * * @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/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* ByElementType */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template<class Stored> inline std::string ByElementType<Stored>::printType(const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; sstr << "(" << ghost_type << ":" << type << ")"; return sstr.str(); } /* -------------------------------------------------------------------------- */ template<class Stored> inline bool ByElementType<Stored>::exists(ElementType type, GhostType ghost_type) const { return this->getData(ghost_type).find(type) != this->getData(ghost_type).end(); } /* -------------------------------------------------------------------------- */ template<class Stored> inline const Stored & ByElementType<Stored>::operator()(const ElementType & type, const GhostType & ghost_type) const { typename DataMap::const_iterator it = this->getData(ghost_type).find(type); if(it == this->getData(ghost_type).end()) AKANTU_EXCEPTION("No element of type " << ByElementType<Stored>::printType(type, ghost_type) << " in this ByElementType<" << debug::demangle(typeid(Stored).name()) << "> class"); return it->second; } /* -------------------------------------------------------------------------- */ template<class Stored> inline Stored & ByElementType<Stored>::operator()(const ElementType & type, const GhostType & ghost_type) { typename DataMap::iterator it = this->getData(ghost_type).find(type); // if(it == this->getData(ghost_type).end()) // AKANTU_EXCEPTION("No element of type " // << ByElementType<Stored>::printType(type, ghost_type) // << " in this ByElementType<" // << debug::demangle(typeid(Stored).name()) << "> class"); if(it == this->getData(ghost_type).end()) { DataMap & data = this->getData(ghost_type); const std::pair<typename DataMap::iterator, bool> & res = data.insert(std::pair<ElementType, Stored>(type, Stored())); it = res.first; } return it->second; } /* -------------------------------------------------------------------------- */ template<class Stored> inline Stored & ByElementType<Stored>::operator()(const Stored & insert, const ElementType & type, const GhostType & ghost_type) { typename DataMap::iterator it = this->getData(ghost_type).find(type); if(it != this->getData(ghost_type).end()) { AKANTU_EXCEPTION("Element of type " << ByElementType<Stored>::printType(type, ghost_type) << " already in this ByElementType<" << debug::demangle(typeid(Stored).name()) << "> class"); } else { DataMap & data = this->getData(ghost_type); const std::pair<typename DataMap::iterator, bool> & res = data.insert(std::pair<ElementType, Stored>(type, insert)); it = res.first; } return it->second; } /* -------------------------------------------------------------------------- */ template<class Stored> inline typename ByElementType<Stored>::DataMap & ByElementType<Stored>::getData(GhostType ghost_type) { if(ghost_type == _not_ghost) return data; else return ghost_data; } /* -------------------------------------------------------------------------- */ template<class Stored> inline const typename ByElementType<Stored>::DataMap & ByElementType<Stored>::getData(GhostType ghost_type) const { if(ghost_type == _not_ghost) return data; else return ghost_data; } /* -------------------------------------------------------------------------- */ /// Works only if stored is a pointer to a class with a printself method template<class Stored> void ByElementType<Stored>::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "ByElementType<" << debug::demangle(typeid(Stored).name()) << "> [" << std::endl; for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; const DataMap & data = getData(gt); typename DataMap::const_iterator it; for(it = data.begin(); it != data.end(); ++it) { stream << space << space << ByElementType<Stored>::printType(it->first, gt) << " [" << std::endl; it->second->printself(stream, indent + 3); } } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ template<class Stored> ByElementType<Stored>::ByElementType(const ID & id, const ID & parent_id) { AKANTU_DEBUG_IN(); std::stringstream sstr; if(parent_id != "") sstr << parent_id << ":"; sstr << id; this->id = sstr.str(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<class Stored> ByElementType<Stored>::~ByElementType() { } /* -------------------------------------------------------------------------- */ template <typename T> inline Vector<T> & ByElementTypeVector<T>::alloc(UInt size, UInt nb_component, const ElementType & type, const GhostType & ghost_type) { std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; Vector<T> * tmp; typename ByElementTypeVector<T>::DataMap::iterator it = this->getData(ghost_type).find(type); if(it == this->getData(ghost_type).end()) { std::stringstream sstr; sstr << this->id << ":" << type << ghost_id; tmp = &(Memory::alloc<T>(sstr.str(), size, nb_component, T())); std::stringstream sstrg; sstrg << ghost_type; tmp->setTag(sstrg.str()); this->getData(ghost_type)[type] = tmp; } else { AKANTU_DEBUG_INFO("The vector " << this->id << this->printType(type, ghost_type) << " already exists, it is resized instead of allocated."); tmp = it->second; it->second->resize(size); } return *tmp; } /* -------------------------------------------------------------------------- */ template <typename T> inline void ByElementTypeVector<T>::alloc(UInt size, UInt nb_component, const ElementType & type) { this->alloc(size, nb_component, type, _not_ghost); this->alloc(size, nb_component, type, _ghost); } /* -------------------------------------------------------------------------- */ template <typename T> inline void ByElementTypeVector<T>::free() { AKANTU_DEBUG_IN(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; const DataMap & data = this->getData(gt); typename DataMap::const_iterator it; for(it = data.begin(); it != data.end(); ++it) { dealloc(it->second->getID()); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> inline const Vector<T> & ByElementTypeVector<T>::operator()(const ElementType & type, const GhostType & ghost_type) const { typename ByElementTypeVector<T>::DataMap::const_iterator it = this->getData(ghost_type).find(type); if(it == this->getData(ghost_type).end()) AKANTU_EXCEPTION("No element of type " << ByElementTypeVector<T>::printType(type, ghost_type) - << " in this ByElementTypeVector<" + << " in this const ByElementTypeVector<" << debug::demangle(typeid(T).name()) << "> class(\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template <typename T> inline Vector<T> & ByElementTypeVector<T>::operator()(const ElementType & type, const GhostType & ghost_type) { typename ByElementTypeVector<T>::DataMap::iterator it = this->getData(ghost_type).find(type); if(it == this->getData(ghost_type).end()) AKANTU_EXCEPTION("No element of type " << ByElementTypeVector<T>::printType(type, ghost_type) << " in this ByElementTypeVector<" << debug::demangle(typeid(T).name()) << "> class (\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template <typename T> inline void ByElementTypeVector<T>::setVector(const ElementType & type, const GhostType & ghost_type, const Vector<T> & vect) { typename ByElementTypeVector<T>::DataMap::iterator it = this->getData(ghost_type).find(type); if(AKANTU_DEBUG_TEST(dblWarning) && it != this->getData(ghost_type).end() && it->second != &vect) { AKANTU_DEBUG_WARNING("The Vector " << this->printType(type, ghost_type) << " is already registred, this call can lead to a memory leak."); } this->getData(ghost_type)[type] = &(const_cast<Vector<T> &>(vect)); } +/* -------------------------------------------------------------------------- */ +template <typename T> +inline void ByElementTypeVector<T>::onElementsRemoved(const ByElementTypeVector<UInt> & new_numbering) { + for(UInt g = _not_ghost; g <= _ghost; ++g) { + GhostType gt = (GhostType) g; + ByElementTypeVector<UInt>::type_iterator it = new_numbering.firstType(0, gt, _ek_not_defined); + ByElementTypeVector<UInt>::type_iterator end = new_numbering.lastType(0, gt, _ek_not_defined); + for (; it != end; ++it) { + ElementType type = *it; + if(this->exists(type, gt)){ + const Vector<UInt> & renumbering = new_numbering(type, gt); + Vector<T> & vect = this->operator()(type, gt); + UInt nb_component = vect.getNbComponent(); + Vector<T> tmp(renumbering.getSize(), nb_component); + UInt new_size = 0; + for (UInt i = 0; i < vect.getSize(); ++i) { + UInt new_i = renumbering(i); + if(new_i != UInt(-1)) { + memcpy(tmp.storage() + new_i * nb_component, + vect.storage() + i *nb_component, + nb_component * sizeof(T)); + ++new_size; + } + } + tmp.resize(new_size); + vect.copy(tmp); + } + } + } +} + /* -------------------------------------------------------------------------- */ /* ElementType Iterator */ /* -------------------------------------------------------------------------- */ template <class Stored> ByElementType<Stored>::type_iterator::type_iterator(DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek) : list_begin(list_begin), list_end(list_end), dim(dim), kind(ek) { } /* -------------------------------------------------------------------------- */ template <class Stored> ByElementType<Stored>::type_iterator::type_iterator(const type_iterator & it) : list_begin(it.list_begin), list_end(it.list_end), dim(it.dim), kind(it.kind) { } /* -------------------------------------------------------------------------- */ template <class Stored> inline typename ByElementType<Stored>::type_iterator::reference ByElementType<Stored>::type_iterator::operator*() { return list_begin->first; } /* -------------------------------------------------------------------------- */ template <class Stored> inline typename ByElementType<Stored>::type_iterator & ByElementType<Stored>::type_iterator::operator++() { ++list_begin; while((list_begin != list_end) && (((dim != 0) && (dim != Mesh::getSpatialDimension(list_begin->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(list_begin->first))))) ++list_begin; return *this; } /* -------------------------------------------------------------------------- */ template <class Stored> typename ByElementType<Stored>::type_iterator ByElementType<Stored>::type_iterator::operator++(int) { type_iterator tmp(*this); operator++(); return tmp; } /* -------------------------------------------------------------------------- */ template <class Stored> inline bool ByElementType<Stored>::type_iterator::operator==(const type_iterator & other) { return this->list_begin == other.list_begin; } /* -------------------------------------------------------------------------- */ template <class Stored> inline bool ByElementType<Stored>::type_iterator::operator!=(const type_iterator & other) { return this->list_begin != other.list_begin; } /* -------------------------------------------------------------------------- */ template <class Stored> inline typename ByElementType<Stored>::type_iterator ByElementType<Stored>::firstType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator b,e; if(ghost_type == _not_ghost) { b = data.begin(); e = data.end(); } else { b = ghost_data.begin(); e = ghost_data.end(); } // loop until the first valid type while((b != e) && (((dim != 0) && (dim != Mesh::getSpatialDimension(b->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(b->first))))) ++b; return typename ByElementType<Stored>::type_iterator(b, e, dim, kind); } /* -------------------------------------------------------------------------- */ template <class Stored> inline typename ByElementType<Stored>::type_iterator ByElementType<Stored>::lastType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator e; if(ghost_type == _not_ghost) { e = data.end(); } else { e = ghost_data.end(); } return typename ByElementType<Stored>::type_iterator(e, e, dim, kind); } diff --git a/src/fem/fem_template.cc b/src/fem/fem_template.cc index ee9ff18e5..edf258135 100644 --- a/src/fem/fem_template.cc +++ b/src/fem/fem_template.cc @@ -1,942 +1,942 @@ /** * @file fem_template.cc * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Fri Feb 11 11:37:47 2011 * * @brief implementation of the generic FEMTemplate class * * @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 "fem.hh" #include "aka_common.hh" #include "shape_lagrange.hh" #include "shape_linked.hh" #include "shape_cohesive.hh" #include "integrator_cohesive.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> FEMTemplate<Integ,Shape>::FEMTemplate(Mesh & mesh, UInt spatial_dimension, ID id, MemoryID memory_id) : FEM(mesh,spatial_dimension,id,memory_id), integrator(mesh, id, memory_id), shape_functions(mesh, id, memory_id) { } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> FEMTemplate<Integ,Shape>::~FEMTemplate() { } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::gradientOnQuadraturePoints(const Vector<Real> &u, Vector<Real> &nablauq, const UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Vector<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 != NULL) nb_element = filter_elements->getSize(); UInt element_dimension = mesh->getSpatialDimension(type); UInt nb_points = shape_functions.getControlPoints(type, ghost_type).getSize(); AKANTU_DEBUG_ASSERT(u.getSize() == 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.getSize() == nb_element * nb_points, "The vector nablauq(" << nablauq.getID() << ") has not the good size."); #endif #define COMPUTE_GRADIENT(type) \ if (element_dimension == ElementClass<type>::getSpatialDimension()) \ shape_functions.template gradientOnControlPoints<type>(u, \ nablauq, \ nb_degree_of_freedom, \ ghost_type, \ filter_elements); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(COMPUTE_GRADIENT); #undef COMPUTE_GRADIENT AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void FEMTemplate<IntegratorCohesive<IntegratorGauss>,ShapeCohesive<ShapeLagrange> >:: initShapeFunctions(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh->getSpatialDimension(); Mesh::type_iterator it = mesh->firstType(element_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator end = mesh->lastType(element_dimension, ghost_type, _ek_cohesive); for(; it != end; ++it) { ElementType type = *it; #define INIT_SHAPE_FUNCTIONS(type) \ integrator.computeQuadraturePoints<type>(ghost_type); \ integrator. \ precomputeJacobiansOnQuadraturePoints<type>(ghost_type); \ integrator. \ checkJacobians<type>(ghost_type); \ const Vector<Real> & control_points = \ integrator.getQuadraturePoints<type>(ghost_type); \ shape_functions. \ setControlPointsByType<type>(control_points, ghost_type); \ shape_functions. \ precomputeShapesOnControlPoints<type>(ghost_type); \ if (element_dimension == spatial_dimension) \ shape_functions. \ precomputeShapeDerivativesOnControlPoints<type>(ghost_type); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS); #undef INIT_SHAPE_FUNCTIONS } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::initShapeFunctions(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh->getSpatialDimension(); Mesh::type_iterator it = mesh->firstType(element_dimension, ghost_type); Mesh::type_iterator end = mesh->lastType(element_dimension, ghost_type); for(; it != end; ++it) { ElementType type = *it; #define INIT_SHAPE_FUNCTIONS(type) \ integrator.template computeQuadraturePoints<type>(ghost_type); \ integrator. \ template precomputeJacobiansOnQuadraturePoints<type>(ghost_type); \ integrator. \ template checkJacobians<type>(ghost_type); \ const Vector<Real> & control_points = \ integrator.template getQuadraturePoints<type>(ghost_type); \ shape_functions. \ template setControlPointsByType<type>(control_points, ghost_type); \ shape_functions. \ template precomputeShapesOnControlPoints<type>(ghost_type); \ if (element_dimension == spatial_dimension) \ shape_functions. \ template precomputeShapeDerivativesOnControlPoints<type>(ghost_type); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS); #undef INIT_SHAPE_FUNCTIONS } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::integrate(const Vector<Real> & f, Vector<Real> &intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Vector<UInt> * filter_elements) const{ #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 != NULL) nb_element = filter_elements->getSize(); UInt nb_quadrature_points = getNbQuadraturePoints(type); AKANTU_DEBUG_ASSERT(f.getSize() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << " size " << f.getSize() << ") has not the good size (" << nb_element << ")."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom , "The vector f(" << f.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom, "The vector intf(" << intf.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getSize() == nb_element, "The vector intf(" << intf.getID() << ") has not the good size."); #endif #define INTEGRATE(type) \ integrator.template integrate<type>(f, \ intf, \ nb_degree_of_freedom, \ ghost_type, \ filter_elements); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> Real FEMTemplate<Integ,Shape>::integrate(const Vector<Real> & f, const ElementType & type, const GhostType & ghost_type, const Vector<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 != NULL) nb_element = filter_elements->getSize(); - UInt nb_quadrature_points = getNbQuadraturePoints(type); + UInt nb_quadrature_points = getNbQuadraturePoints(type, ghost_type); AKANTU_DEBUG_ASSERT(f.getSize() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() - << ") has not the good size."); + << ") has not the good size. (" << f.getSize() << "!=" << 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 = 0.; #define INTEGRATE(type) \ integral = integrator.template integrate<type>(f, \ ghost_type, \ filter_elements); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE AKANTU_DEBUG_OUT(); return integral; } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::integrateOnQuadraturePoints(const Vector<Real> & f, Vector<Real> &intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Vector<UInt> * filter_elements) const{ #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 != NULL) nb_element = filter_elements->getSize(); UInt nb_quadrature_points = getNbQuadraturePoints(type); AKANTU_DEBUG_ASSERT(f.getSize() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << " size " << f.getSize() << ") has not the good size (" << nb_element << ")."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom , "The vector f(" << f.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom, "The vector intf(" << intf.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getSize() == nb_element * nb_quadrature_points, "The vector intf(" << intf.getID() << ") has not the good size."); #endif #define INTEGRATE(type) \ integrator.template integrateOnQuadraturePoints<type>(f, \ intf, \ nb_degree_of_freedom, \ ghost_type, \ filter_elements); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::interpolateOnQuadraturePoints(const Vector<Real> &u, Vector<Real> &uq, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Vector<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 != NULL) nb_element = filter_elements->getSize(); UInt nb_points = shape_functions.getControlPoints(type, ghost_type).getSize(); AKANTU_DEBUG_ASSERT(u.getSize() == 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."); AKANTU_DEBUG_ASSERT(uq.getSize() == nb_element * nb_points, "The vector uq(" << uq.getID() << ") has not the good size."); #endif #define INTERPOLATE(type) \ shape_functions.template interpolateOnControlPoints<type>(u, \ uq, \ nb_degree_of_freedom, \ ghost_type, \ filter_elements); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INTERPOLATE); #undef INTERPOLATE AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::computeNormalsOnControlPoints(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); computeNormalsOnControlPoints(mesh->getNodes(), ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::computeNormalsOnControlPoints(const Vector<Real> & field, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); if (ghost_type == _ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } // Real * coord = mesh->getNodes().values; UInt spatial_dimension = mesh->getSpatialDimension(); //allocate the normal arrays mesh->initByElementTypeVector(normals_on_quad_points, spatial_dimension, element_dimension); //loop over the type to build the normals Mesh::type_iterator it = mesh->firstType(element_dimension, ghost_type); Mesh::type_iterator end = mesh->lastType(element_dimension, ghost_type); for(; it != end; ++it) { Vector<Real> & normals_on_quad = normals_on_quad_points(*it, ghost_type); computeNormalsOnControlPoints(field, normals_on_quad, *it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::computeNormalsOnControlPoints(const Vector<Real> & field, Vector<Real> & normal, const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); if (ghost_type == _ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } UInt spatial_dimension = mesh->getSpatialDimension(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quad_points = getQuadraturePoints(type, ghost_type).getSize(); UInt * elem_val = mesh->getConnectivity(type, ghost_type).storage(); UInt nb_element = mesh->getConnectivity(type, ghost_type).getSize(); normal.resize(nb_element * nb_quad_points); Real * normals_on_quad_val = normal.storage(); /* ---------------------------------------------------------------------- */ #define COMPUTE_NORMALS_ON_QUAD(type) \ do { \ const Vector<Real> & quads = \ integrator. template getQuadraturePoints<type>(ghost_type); \ UInt nb_points = quads.getSize(); \ Real local_coord[spatial_dimension * nb_nodes_per_element]; \ for (UInt elem = 0; elem < nb_element; ++elem) { \ mesh->extractNodalValuesFromElement(field, \ local_coord, \ elem_val+elem*nb_nodes_per_element, \ nb_nodes_per_element, \ spatial_dimension); \ \ ElementClass<type>::computeNormalsOnQuadPoint(local_coord, \ spatial_dimension, \ normals_on_quad_val); \ normals_on_quad_val += spatial_dimension*nb_points; \ } \ } while(0) /* ---------------------------------------------------------------------- */ AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(COMPUTE_NORMALS_ON_QUAD); #undef COMPUTE_NORMALS_ON_QUAD AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* compatibility functions */ /* -------------------------------------------------------------------------- */ template <> inline UInt FEMTemplate<IntegratorCohesive<IntegratorGauss>,ShapeCohesive<ShapeLagrange> > ::getNbQuadraturePoints(const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt nb_quad_points = 0; #define GET_NB_QUAD(type) \ nb_quad_points = \ integrator. getQuadraturePoints<type>(ghost_type).getSize(); // AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_NB_QUAD); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(GET_NB_QUAD); #undef GET_NB_QUAD AKANTU_DEBUG_OUT(); return nb_quad_points; } /* -------------------------------------------------------------------------- */ template <> Real FEMTemplate<IntegratorCohesive<IntegratorGauss>,ShapeCohesive<ShapeLagrange> >::integrate(const Vector<Real> & f, const ElementType & type, const GhostType & ghost_type, const Vector<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 != NULL) nb_element = filter_elements->getSize(); UInt nb_quadrature_points = getNbQuadraturePoints(type); AKANTU_DEBUG_ASSERT(f.getSize() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << ") has not the good size."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == 1, "The vector f(" << f.getID() << ") has not the good number of component."); #endif Real integral = 0.; #define INTEGRATE(type) \ integral = integrator. integrate<type>(f, \ ghost_type, \ filter_elements); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE AKANTU_DEBUG_OUT(); return integral; } /* -------------------------------------------------------------------------- */ template <> void FEMTemplate<IntegratorCohesive<IntegratorGauss>,ShapeCohesive<ShapeLagrange> > ::integrate(const Vector<Real> & f, Vector<Real> &intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Vector<UInt> * filter_elements) const{ #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 != NULL) nb_element = filter_elements->getSize(); UInt nb_quadrature_points = getNbQuadraturePoints(type); AKANTU_DEBUG_ASSERT(f.getSize() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << " size " << f.getSize() << ") has not the good size (" << nb_element << ")."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom , "The vector f(" << f.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom, "The vector intf(" << intf.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getSize() == nb_element, "The vector intf(" << intf.getID() << ") has not the good size."); #endif #define INTEGRATE(type) \ integrator. integrate<type>(f, \ intf, \ nb_degree_of_freedom, \ ghost_type, \ filter_elements); // AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INTEGRATE); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> inline UInt FEMTemplate<Integ,Shape>::getNbQuadraturePoints(const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt nb_quad_points = 0; #define GET_NB_QUAD(type) \ nb_quad_points = \ integrator. template getQuadraturePoints<type>(ghost_type).getSize(); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_NB_QUAD); #undef GET_NB_QUAD AKANTU_DEBUG_OUT(); return nb_quad_points; } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> inline const Vector<Real> & FEMTemplate<Integ,Shape>::getShapes(const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); const Vector<Real> * ret = NULL; #define GET_SHAPES(type) \ ret = &(shape_functions.getShapes(type, ghost_type)); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_SHAPES); #undef GET_SHAPES AKANTU_DEBUG_OUT(); return *ret; } /* -------------------------------------------------------------------------- */ template <> inline const Vector<Real> & FEMTemplate<IntegratorCohesive<IntegratorGauss>,ShapeCohesive<ShapeLagrange> > ::getShapes(const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); const Vector<Real> * ret = NULL; #define GET_SHAPES(type) \ ret = &(shape_functions.getShapes(type, ghost_type)); // AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_SHAPES); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(GET_SHAPES); #undef GET_SHAPES AKANTU_DEBUG_OUT(); return *ret; } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> inline const Vector<Real> & FEMTemplate<Integ,Shape>::getShapesDerivatives(const ElementType & type, const GhostType & ghost_type, __attribute__((unused)) UInt id) const { AKANTU_DEBUG_IN(); const Vector<Real> * ret = NULL; #define GET_SHAPES(type) \ ret = &(shape_functions.getShapesDerivatives(type, ghost_type)); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_SHAPES); #undef GET_SHAPES AKANTU_DEBUG_OUT(); return *ret; } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> inline const Vector<Real> & FEMTemplate<Integ,Shape>::getQuadraturePoints(const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); const Vector<Real> * ret = NULL; #define GET_QUADS(type) \ ret = &(integrator. template getQuadraturePoints<type>(ghost_type)); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_QUADS); #undef GET_QUADS AKANTU_DEBUG_OUT(); return *ret; } /* -------------------------------------------------------------------------- */ /* Matrix lumping functions */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::assembleFieldLumped(const Vector<Real> & field_1, UInt nb_degree_of_freedom, Vector<Real> & lumped, const Vector<Int> & equation_number, ElementType type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); #define ASSEMBLE_LUMPED(type) \ assembleLumpedTemplate<type>(field_1, nb_degree_of_freedom,lumped, equation_number,ghost_type) AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(ASSEMBLE_LUMPED);; #undef ASSEMBLE_LUMPED AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> inline const Vector<Real> & FEMTemplate<IntegratorGauss, ShapeLinked>::getShapesDerivatives(const ElementType & type, const GhostType & ghost_type, UInt id) const { AKANTU_DEBUG_IN(); const Vector<Real> * ret = NULL; #define GET_SHAPES(type) \ ret = &(shape_functions.getShapesDerivatives(type, ghost_type, id)); AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_SHAPES); #undef GET_SHAPES AKANTU_DEBUG_OUT(); return *ret; } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> void FEMTemplate<Integ,Shape>::assembleFieldMatrix(const Vector<Real> & field_1, UInt nb_degree_of_freedom, SparseMatrix & matrix, ElementType type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); #define ASSEMBLE_MATRIX(type) \ assembleFieldMatrix<type>(field_1, nb_degree_of_freedom, \ matrix, \ ghost_type) AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(ASSEMBLE_MATRIX);; #undef ASSEMBLE_MATRIX AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Integ, typename Shape> template <ElementType type> void FEMTemplate<Integ,Shape>::assembleLumpedTemplate(const Vector<Real> & field_1, UInt nb_degree_of_freedom, Vector<Real> & lumped, const Vector<Int> & equation_number, const GhostType & ghost_type) const { this->template assembleLumpedRowSum<type>(field_1, nb_degree_of_freedom,lumped, equation_number,ghost_type); } /* -------------------------------------------------------------------------- */ //template <typename Integ, typename Shape> template <> template <> void FEMTemplate<IntegratorGauss,ShapeLagrange>:: assembleLumpedTemplate<_triangle_6>(const Vector<Real> & field_1, UInt nb_degree_of_freedom, Vector<Real> & lumped, const Vector<Int> & equation_number, const GhostType & ghost_type) const { assembleLumpedDiagonalScaling<_triangle_6>(field_1, nb_degree_of_freedom,lumped, equation_number,ghost_type); } /* -------------------------------------------------------------------------- */ template <> template <> void FEMTemplate<IntegratorGauss,ShapeLagrange>:: assembleLumpedTemplate<_tetrahedron_10>(const Vector<Real> & field_1, UInt nb_degree_of_freedom, Vector<Real> & lumped, const Vector<Int> & equation_number, const GhostType & ghost_type) const { assembleLumpedDiagonalScaling<_tetrahedron_10>(field_1, nb_degree_of_freedom,lumped, equation_number,ghost_type); } /* -------------------------------------------------------------------------- */ template <> template <> void FEMTemplate<IntegratorGauss,ShapeLagrange>::assembleLumpedTemplate<_quadrangle_8>(const Vector<Real> & field_1, UInt nb_degree_of_freedom, Vector<Real> & lumped, const Vector<Int> & equation_number, const GhostType & ghost_type) const { assembleLumpedDiagonalScaling<_quadrangle_8>(field_1, nb_degree_of_freedom,lumped, equation_number, ghost_type); } /* -------------------------------------------------------------------------- */ /** * @f$ \tilde{M}_{i} = \sum_j M_{ij} = \sum_j \int \rho \varphi_i \varphi_j dV = \int \rho \varphi_i dV @f$ */ template <typename Integ, typename Shape> template <ElementType type> void FEMTemplate<Integ,Shape>::assembleLumpedRowSum(const Vector<Real> & field_1, UInt nb_degree_of_freedom, Vector<Real> & lumped, const Vector<Int> & equation_number, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt shapes_size = ElementClass<type>::getShapeSize(); Vector<Real> * field_times_shapes = new Vector<Real>(0, 1);//shapes_size); shape_functions.template fieldTimesShapes<type>(field_1, *field_times_shapes, ghost_type); UInt nb_element = mesh->getNbElement(type, ghost_type); Vector<Real> * int_field_times_shapes = new Vector<Real>(nb_element, shapes_size, "inte_rho_x_shapes"); integrator.template integrate<type>(*field_times_shapes, *int_field_times_shapes, shapes_size, ghost_type, NULL); delete field_times_shapes; int_field_times_shapes->extendComponentsInterlaced(nb_degree_of_freedom,1); assembleVector(*int_field_times_shapes, lumped, equation_number,nb_degree_of_freedom, type, ghost_type); delete int_field_times_shapes; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @f$ \tilde{M}_{i} = c * M_{ii} = \int_{V_e} \rho dV @f$ */ template <typename Integ, typename Shape> template <ElementType type> void FEMTemplate<Integ,Shape>::assembleLumpedDiagonalScaling(const Vector<Real> & field_1, UInt nb_degree_of_freedom, Vector<Real> & lumped, const Vector<Int> & equation_number, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element_p1 = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type)); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = integrator.template getQuadraturePoints<type>(ghost_type).getSize(); UInt nb_element = field_1.getSize() / nb_quadrature_points; Real corner_factor = 0; Real mid_factor = 0; if(type == _triangle_6) { corner_factor = 1./12.; mid_factor = 1./4.; } if (type == _tetrahedron_10) { corner_factor = 1./32.; mid_factor = 7./48.; } if (type == _quadrangle_8) { corner_factor = 1./36.; mid_factor = 8./36.; } if (nb_element == 0) { AKANTU_DEBUG_OUT(); return; } /// compute @f$ \int \rho dV = \rho V @f$ for each element Vector<Real> * int_field_1 = new Vector<Real>(field_1.getSize(), 1, "inte_rho_x_1"); integrator.template integrate<type>(field_1, *int_field_1, 1, ghost_type, NULL); /// distribute the mass of the element to the nodes Vector<Real> * lumped_per_node = new Vector<Real>(nb_element, nb_nodes_per_element, "mass_per_node"); Real * int_field_1_val = int_field_1->values; Real * lumped_per_node_val = lumped_per_node->values; for (UInt e = 0; e < nb_element; ++e) { Real lmass = *int_field_1_val * corner_factor; for (UInt n = 0; n < nb_nodes_per_element_p1; ++n) *lumped_per_node_val++ = lmass; /// corner points lmass = *int_field_1_val * mid_factor; for (UInt n = nb_nodes_per_element_p1; n < nb_nodes_per_element; ++n) *lumped_per_node_val++ = lmass; /// mid points int_field_1_val++; } delete int_field_1; lumped_per_node->extendComponentsInterlaced(nb_degree_of_freedom,1); assembleVector(*lumped_per_node, lumped, equation_number, nb_degree_of_freedom, type, ghost_type); delete lumped_per_node; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @f$ \tilde{M}_{i} = \sum_j M_{ij} = \sum_j \int \rho \varphi_i \varphi_j dV = \int \rho \varphi_i dV @f$ */ template <typename Integ, typename Shape> template <ElementType type> void FEMTemplate<Integ,Shape>::assembleFieldMatrix(const Vector<Real> & field_1, UInt nb_degree_of_freedom, SparseMatrix & matrix, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt vect_size = field_1.getSize(); UInt shapes_size = ElementClass<type>::getShapeSize(); UInt lmat_size = nb_degree_of_freedom * shapes_size; const Vector<Real> & shapes = shape_functions.getShapes(type,ghost_type); Vector<Real> * modified_shapes = new Vector<Real>(vect_size, lmat_size * nb_degree_of_freedom); modified_shapes->clear(); Vector<Real> * local_mat = new Vector<Real>(vect_size, lmat_size * lmat_size); Vector<Real>::iterator<types::Matrix> shape_vect = modified_shapes->begin(nb_degree_of_freedom, lmat_size); Real * sh = shapes.values; for(UInt q = 0; q < vect_size; ++q) { Real * msh = shape_vect->storage(); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { Real * msh_tmp = msh + d * (lmat_size + 1); for (UInt s = 0; s < shapes_size; ++s) { *msh_tmp = sh[s]; msh_tmp += nb_degree_of_freedom; } } ++shape_vect; sh += shapes_size; } shape_vect = modified_shapes->begin(nb_degree_of_freedom, lmat_size); Vector<Real>::iterator<types::Matrix> lmat = local_mat->begin(lmat_size, lmat_size); Real * field_val = field_1.values; for(UInt q = 0; q < vect_size; ++q) { (*lmat).mul<true, false>(*shape_vect, *shape_vect, *field_val); ++lmat; ++shape_vect; ++field_val; } delete modified_shapes; UInt nb_element = mesh->getNbElement(type, ghost_type); Vector<Real> * int_field_times_shapes = new Vector<Real>(nb_element, lmat_size * lmat_size, "inte_rho_x_shapes"); integrator.template integrate<type>(*local_mat, *int_field_times_shapes, lmat_size * lmat_size, ghost_type, NULL); delete local_mat; assembleMatrix(*int_field_times_shapes, matrix, nb_degree_of_freedom, type, ghost_type); delete int_field_times_shapes; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void FEMTemplate< IntegratorCohesive<IntegratorGauss>, ShapeCohesive<ShapeLagrange> >:: gradientOnQuadraturePoints(__attribute__((unused)) const Vector<Real> &u, __attribute__((unused)) Vector<Real> &nablauq, __attribute__((unused)) const UInt nb_degree_of_freedom, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type, __attribute__((unused)) const Vector<UInt> * filter_elements) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ /* template instanciation */ /* -------------------------------------------------------------------------- */ template class FEMTemplate<IntegratorGauss,ShapeLagrange>; template class FEMTemplate<IntegratorGauss,ShapeLinked>; template class FEMTemplate< IntegratorCohesive<IntegratorGauss>, ShapeCohesive<ShapeLagrange> >; __END_AKANTU__ diff --git a/src/fem/integrator_gauss.cc b/src/fem/integrator_gauss.cc index 097ede554..4cd71893d 100644 --- a/src/fem/integrator_gauss.cc +++ b/src/fem/integrator_gauss.cc @@ -1,328 +1,331 @@ /** * @file integrator_gauss.cc * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Feb 10 16:52:07 2011 * * @brief implementation of gauss integrator class * * @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.hh" #include "integrator_gauss.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ IntegratorGauss::IntegratorGauss(const Mesh & mesh, const ID & id, const MemoryID & memory_id) : Integrator(mesh, id, memory_id), quadrature_points("quadrature_points", id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void IntegratorGauss::checkJacobians(const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = ElementClass<type>::getNbQuadraturePoints(); UInt nb_element; nb_element = mesh->getConnectivity(type,ghost_type).getSize(); Real * jacobians_val = jacobians(type, ghost_type).storage(); for (UInt i = 0; i < nb_element*nb_quadrature_points; ++i,++jacobians_val){ - AKANTU_DEBUG_ASSERT(*jacobians_val >0, - "Negative jacobian computed," - << " possible problem in the element node ordering (element " << i -/nb_quadrature_points << ")"); + if(*jacobians_val < 0) + AKANTU_DEBUG_ERROR("Negative jacobian computed," + << " possible problem in the element node ordering (Quadrature Point " + << i % nb_quadrature_points << ":" + << i / nb_quadrature_points << ":" + << type << ":" + << ghost_type << ")"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void IntegratorGauss::precomputeJacobiansOnQuadraturePoints(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh->getSpatialDimension(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = ElementClass<type>::getNbQuadraturePoints(); Real * weights = ElementClass<type>::getGaussIntegrationWeights(); UInt * elem_val = mesh->getConnectivity(type,ghost_type).storage(); UInt nb_element = mesh->getConnectivity(type,ghost_type).getSize(); Vector<Real> & jacobians_tmp = jacobians.alloc(nb_element*nb_quadrature_points, 1, type, ghost_type); Real * jacobians_val = jacobians_tmp.storage(); Real local_coord[spatial_dimension * nb_nodes_per_element]; for (UInt elem = 0; elem < nb_element; ++elem) { mesh->extractNodalValuesFromElement(mesh->getNodes(), local_coord, elem_val+elem*nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); computeJacobianOnQuadPointsByElement<type>(spatial_dimension, local_coord, nb_nodes_per_element, jacobians_val); for (UInt q = 0; q < nb_quadrature_points; ++q) { *jacobians_val++ *= weights[q]; } // jacobians_val += nb_quadrature_points; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void IntegratorGauss::integrate(const Vector<Real> & in_f, Vector<Real> &intf, UInt nb_degree_of_freedom, const GhostType & ghost_type, const Vector<UInt> * filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); UInt nb_element = mesh->getNbElement(type,ghost_type); const Vector<Real> & jac_loc = jacobians(type, ghost_type); UInt nb_quadrature_points = ElementClass<type>::getNbQuadraturePoints(); UInt * filter_elem_val = NULL; if(filter_elements != NULL) { nb_element = filter_elements->getSize(); filter_elem_val = filter_elements->values; } Real * in_f_val = in_f.storage(); Real * intf_val = intf.storage(); Real * jac_val = jac_loc.storage(); UInt offset_in_f = in_f.getNbComponent()*nb_quadrature_points; UInt offset_intf = intf.getNbComponent(); Real * jac = jac_val; for (UInt el = 0; el < nb_element; ++el) { if(filter_elements != NULL) { jac = jac_val + filter_elem_val[el] * nb_quadrature_points; } integrate(in_f_val, jac, intf_val, nb_degree_of_freedom, nb_quadrature_points); in_f_val += offset_in_f; intf_val += offset_intf; if(filter_elements == NULL) { jac += nb_quadrature_points; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> Real IntegratorGauss::integrate(const Vector<Real> & in_f, const GhostType & ghost_type, const Vector<UInt> * filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); UInt nb_element = mesh->getNbElement(type, ghost_type); const Vector<Real> & jac_loc = jacobians(type, ghost_type); UInt nb_quadrature_points = ElementClass<type>::getNbQuadraturePoints(); UInt * filter_elem_val = NULL; if(filter_elements != NULL) { nb_element = filter_elements->getSize(); filter_elem_val = filter_elements->values; } Real intf = 0.; Real * in_f_val = in_f.storage(); Real * jac_val = jac_loc.storage(); UInt offset_in_f = in_f.getNbComponent() * nb_quadrature_points; Real * jac = jac_val; for (UInt el = 0; el < nb_element; ++el) { if(filter_elements != NULL) { jac = jac_val + filter_elem_val[el] * nb_quadrature_points; } Real el_intf = 0; integrate(in_f_val, jac, &el_intf, 1, nb_quadrature_points); intf += el_intf; in_f_val += offset_in_f; if(filter_elements == NULL) { jac += nb_quadrature_points; } } AKANTU_DEBUG_OUT(); return intf; } /* -------------------------------------------------------------------------- */ template <ElementType type> void IntegratorGauss::integrateOnQuadraturePoints(const Vector<Real> & in_f, Vector<Real> &intf, UInt nb_degree_of_freedom, const GhostType & ghost_type, const Vector<UInt> * filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); UInt nb_element = mesh->getNbElement(type,ghost_type); const Vector<Real> & jac_loc = jacobians(type, ghost_type); UInt nb_quadrature_points = ElementClass<type>::getNbQuadraturePoints(); UInt * filter_elem_val = NULL; if(filter_elements != NULL) { nb_element = filter_elements->getSize(); filter_elem_val = filter_elements->values; } Real * in_f_val = in_f.storage(); Real * intf_val = intf.storage(); Real * jac_val = jac_loc.storage(); Real * jac = jac_val; for (UInt el = 0; el < nb_element; ++el) { if(filter_elements != NULL) { jac = jac_val + filter_elem_val[el] * nb_quadrature_points; } for (UInt q = 0; q < nb_quadrature_points; ++q) { for (UInt dof = 0; dof < nb_degree_of_freedom; ++dof) { *intf_val = *in_f_val * *jac; ++in_f_val; ++intf_val; } ++jac; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void IntegratorGauss::precomputeJacobiansOnQuadraturePoints<_bernoulli_beam_2>(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh->getSpatialDimension(); UInt nb_quadrature_points = ElementClass<_bernoulli_beam_2>::getNbQuadraturePoints(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_bernoulli_beam_2); UInt * elem_val; UInt nb_element; elem_val = mesh->getConnectivity(_bernoulli_beam_2, ghost_type).storage(); nb_element = mesh->getConnectivity(_bernoulli_beam_2, ghost_type).getSize(); Vector<Real> & jacobians_tmp = jacobians.alloc(nb_element*nb_quadrature_points, 1, _bernoulli_beam_2, ghost_type); Real local_coord[spatial_dimension * nb_nodes_per_element]; Real * jacobians_val = jacobians_tmp.storage(); for (UInt elem = 0; elem < nb_element; ++elem) { mesh->extractNodalValuesFromElement(mesh->getNodes(), local_coord, elem_val+elem*nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); ElementClass<_bernoulli_beam_2>::computeJacobian(local_coord, nb_quadrature_points, spatial_dimension, jacobians_val); jacobians_val += nb_quadrature_points; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* template instanciation */ /* -------------------------------------------------------------------------- */ #define INSTANCIATE_TEMPLATE_CLASS(type) \ template void IntegratorGauss:: \ precomputeJacobiansOnQuadraturePoints<type>(const GhostType & ghost_type); \ template void IntegratorGauss:: \ checkJacobians<type>(const GhostType & ghost_type) const; \ template void IntegratorGauss:: \ integrate<type>(const Vector<Real> & in_f, \ Vector<Real> &intf, \ UInt nb_degree_of_freedom, \ const GhostType & ghost_type, \ const Vector<UInt> * filter_elements) const; \ template Real IntegratorGauss:: \ integrate<type>(const Vector<Real> & in_f, \ const GhostType & ghost_type, \ const Vector<UInt> * filter_elements) const; \ template void IntegratorGauss:: \ integrateOnQuadraturePoints<type>(const Vector<Real> & in_f, \ Vector<Real> &intf, \ UInt nb_degree_of_freedom, \ const GhostType & ghost_type, \ const Vector<UInt> * filter_elements) const; AKANTU_BOOST_REGULAR_ELEMENT_LIST(INSTANCIATE_TEMPLATE_CLASS) #undef INSTANCIATE_TEMPLATE_CLASS __END_AKANTU__ diff --git a/src/fem/mesh.cc b/src/fem/mesh.cc index 9236f3111..be2db690d 100644 --- a/src/fem/mesh.cc +++ b/src/fem/mesh.cc @@ -1,308 +1,315 @@ /** * @file mesh.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Wed Jun 16 12:02:26 2010 * * @brief class handling meshes * * @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 <sstream> /* -------------------------------------------------------------------------- */ #include "mesh.hh" #include "element_class.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const Element ElementNull(_not_defined, 0); /* -------------------------------------------------------------------------- */ void Element::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Element [" << type << ", " << element << ", " << ghost_type << "]"; } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : Memory(memory_id), id(id), nodes_global_ids(NULL), nodes_type(NULL), created_nodes(true), connectivities("connectivities", id), normals("normals", id), spatial_dimension(spatial_dimension), types_offsets(Vector<UInt>((UInt) _max_element_type + 1, 1)), ghost_types_offsets(Vector<UInt>((UInt) _max_element_type + 1, 1)), nb_surfaces(0), surface_id("surface_id", id), element_to_subelement("element_to_subelement", id), subelement_to_element("subelement_to_element", id), uint_data("by_element_uint_data", id) { AKANTU_DEBUG_IN(); std::stringstream sstr; sstr << id << ":coordinates"; this->nodes = &(alloc<Real>(sstr.str(), 0, this->spatial_dimension)); nb_global_nodes = 0; init(); std::fill_n(lower_bounds, 3, 0.); std::fill_n(upper_bounds, 3, 0.); std::fill_n(size, 3, 0.); std::fill_n(local_lower_bounds, 3, 0.); std::fill_n(local_upper_bounds, 3, 0.); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, const MemoryID & memory_id) : Memory(memory_id), id(id), nodes_global_ids(NULL), nodes_type(NULL), created_nodes(false), connectivities("connectivities", id), normals("normals", id), spatial_dimension(spatial_dimension), types_offsets(Vector<UInt>((UInt) _max_element_type + 1, 1)), ghost_types_offsets(Vector<UInt>((UInt) _max_element_type + 1, 1)), nb_surfaces(0), surface_id("surface_id", id), element_to_subelement("element_to_subelement", id), subelement_to_element("subelement_to_element", id), uint_data("by_element_uint_data", id) { AKANTU_DEBUG_IN(); this->nodes = &(getVector<Real>(nodes_id)); nb_global_nodes = nodes->getSize(); init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, Vector<Real> & nodes, const ID & id, const MemoryID & memory_id) : Memory(memory_id), id(id), nodes_global_ids(NULL), nodes_type(NULL), created_nodes(false), connectivities("connectivities", id), normals("normals", id), spatial_dimension(spatial_dimension), types_offsets(Vector<UInt>(_max_element_type + 1, 1)), ghost_types_offsets(Vector<UInt>(_max_element_type + 1, 1)), nb_surfaces(0), surface_id("surface_id", id), element_to_subelement("element_to_subelement", id), subelement_to_element("subelement_to_element", id), uint_data("by_element_uint_data", id) { AKANTU_DEBUG_IN(); this->nodes = &(nodes); nb_global_nodes = nodes.getSize(); init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::init() { // this->types_offsets.resize(_max_element_type); nodes_type = NULL; computeBoundingBox(); } /* -------------------------------------------------------------------------- */ Mesh::~Mesh() { AKANTU_DEBUG_IN(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = firstType(0, gt); Mesh::type_iterator end = lastType(0, gt); for(; it != end; ++it) { UIntDataMap & map = uint_data(*it, gt); UIntDataMap::iterator dit; for (dit = map.begin(); dit != map.end(); ++dit) { if(dit->second) delete dit->second; } map.clear(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ 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 : " << this->id << std::endl; stream << space << " + spatial dimension : " << this->spatial_dimension << std::endl; stream << space << " + nodes [" << std::endl; nodes->printself(stream, indent+2); stream << space << " ]" << std::endl; stream << space << " + connectivities [" << std::endl; connectivities.printself(stream, indent+2); 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->getSize(); ++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)); } } StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Real reduce_bounds[2 * spatial_dimension]; for (UInt k = 0; k < spatial_dimension; ++k) { reduce_bounds[2*k ] = local_lower_bounds[k]; reduce_bounds[2*k + 1] = - local_upper_bounds[k]; } comm.allReduce(reduce_bounds, 2 * spatial_dimension, _so_min); for (UInt k = 0; k < spatial_dimension; ++k) { lower_bounds[k] = reduce_bounds[2*k]; upper_bounds[k] = - reduce_bounds[2*k + 1]; } for (UInt k = 0; k < spatial_dimension; ++k) size[k] = upper_bounds[k] - lower_bounds[k]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::setSurfaceIDsFromIntData(const std::string & data_name) { std::set<Surface> surface_ids; for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = firstType(spatial_dimension - 1, gt); Mesh::type_iterator end = lastType(spatial_dimension - 1, gt); for(; it != end; ++it) { UIntDataMap & map = uint_data(*it, gt); UIntDataMap::iterator it_data = map.find(data_name); AKANTU_DEBUG_ASSERT(it_data != map.end(), "No data named " << data_name << " present in the mesh " << id << " for the element type " << *it); AKANTU_DEBUG_ASSERT(!surface_id.exists(*it, gt), "Surface id for type (" << gt << ":" << *it << ") already set to the vector " << surface_id(*it, gt).getID()); surface_id.setVector(*it, gt, *it_data->second); for (UInt s = 0; s < it_data->second->getSize(); ++s) { surface_ids.insert((*it_data->second)(s)); } } } nb_surfaces = surface_ids.size(); } /* -------------------------------------------------------------------------- */ template<typename T> void Mesh::initByElementTypeVector(ByElementTypeVector<T> & vect, UInt nb_component, UInt dim, const bool & flag_nb_node_per_elem_multiply, - ElementKind element_kind) const { + ElementKind element_kind, + bool size_to_nb_element) const { AKANTU_DEBUG_IN(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = firstType(dim, gt, element_kind); Mesh::type_iterator end = lastType(dim, gt, element_kind); for(; it != end; ++it) { ElementType type = *it; if (flag_nb_node_per_elem_multiply) nb_component *= Mesh::getNbNodesPerElement(*it); - vect.alloc(0, nb_component, type); + UInt size = 0; + if (size_to_nb_element) size = this->getNbElement(type, gt); + vect.alloc(size, nb_component, type); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Mesh::initByElementTypeVector<Real>(ByElementTypeVector<Real> & vect, UInt nb_component, UInt dim, const bool & flag_nb_elem_multiply, - ElementKind element_kind) const; + ElementKind element_kind, + bool size_to_nb_element) const; template void Mesh::initByElementTypeVector<Int>(ByElementTypeVector<Int> & vect, UInt nb_component, UInt dim, const bool & flag_nb_elem_multiply, - ElementKind element_kind) const; + ElementKind element_kind, + bool size_to_nb_element) const; template void Mesh::initByElementTypeVector<UInt>(ByElementTypeVector<UInt> & vect, UInt nb_component, UInt dim, const bool & flag_nb_elem_multiply, - ElementKind element_kind) const; + ElementKind element_kind, + bool size_to_nb_element) const; template void Mesh::initByElementTypeVector<bool>(ByElementTypeVector<bool> & vect, UInt nb_component, UInt dim, const bool & flag_nb_elem_multiply, - ElementKind element_kind) const; + ElementKind element_kind, + bool size_to_nb_element) const; __END_AKANTU__ diff --git a/src/fem/mesh.hh b/src/fem/mesh.hh index 99d2074b8..b47b6b8bd 100644 --- a/src/fem/mesh.hh +++ b/src/fem/mesh.hh @@ -1,553 +1,595 @@ /** * @file mesh.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Wed Jun 16 11:53:53 2010 * * @brief the class representing the meshes * * @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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_HH__ #define __AKANTU_MESH_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "aka_vector.hh" #include "element_class.hh" #include "by_element_type.hh" #include "aka_event_handler.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Element */ /* -------------------------------------------------------------------------- */ class Element { public: Element(ElementType type = _not_defined, UInt element = 0, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) : type(type), element(element), ghost_type(ghost_type), kind(kind) {}; Element(const Element & element) { this->type = element.type; this->element = element.element; this->ghost_type = element.ghost_type; this->kind = element.kind; } inline bool operator==(const Element & elem) const { return ((element == elem.element) && (type == elem.type) && (ghost_type == elem.ghost_type) && (kind == elem.kind)); } inline bool operator!=(const Element & elem) const { return ((element != elem.element) || (type != elem.type) || (ghost_type != elem.ghost_type) || (kind != elem.kind)); } + bool operator<(const Element& rhs) const { + bool res = ((this->kind < rhs.kind) || + ((this->kind == rhs.kind) && + ((this->ghost_type < rhs.ghost_type) || + ((this->ghost_type == rhs.ghost_type) && + ((this->type < rhs.type) || + ((this->type == rhs.type) && + (this->element < rhs.element))))))); + return res; + } virtual ~Element() {}; /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; public: ElementType type; UInt element; GhostType ghost_type; ElementKind kind; }; struct CompElementLess { bool operator() (const Element& lhs, const Element& rhs) const { - bool res = ((lhs.kind < rhs.kind) || - ((lhs.kind == rhs.kind) && - ((lhs.ghost_type < rhs.ghost_type) || - ((lhs.ghost_type == rhs.ghost_type) && - ((lhs.type < rhs.type) || - ((lhs.type == rhs.type) && - (lhs.element < rhs.element))))))); - return res; + return lhs < rhs; } }; extern const Element ElementNull; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* Mesh modifications events */ /* -------------------------------------------------------------------------- */ template<class Entity> class MeshEvent { public: const Vector<Entity> & getList() const { return list; } Vector<Entity> & getList() { return list; } protected: Vector<Entity> list; }; + + +class Mesh; + class NewNodesEvent : public MeshEvent<UInt> { }; -class RemovedNodesEvent : public MeshEvent<UInt> { }; +class RemovedNodesEvent : public MeshEvent<UInt> { +public: + inline RemovedNodesEvent(const Mesh & mesh); + AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, Vector<UInt> &); + AKANTU_GET_MACRO(NewNumbering, new_numbering, const Vector<UInt> &); +private: + Vector<UInt> new_numbering; +}; + class NewElementsEvent : public MeshEvent<Element> { }; -class RemovedElementsEvent : public MeshEvent<Element> { }; +class RemovedElementsEvent : public MeshEvent<Element> { +public: + inline RemovedElementsEvent(const Mesh & mesh); + AKANTU_GET_MACRO(NewNumbering, new_numbering, const ByElementTypeUInt &); + AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, ByElementTypeUInt &); + AKANTU_GET_MACRO_BY_ELEMENT_TYPE(NewNumbering, new_numbering, UInt); + AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(NewNumbering, new_numbering, UInt); +protected: + ByElementTypeUInt new_numbering; +}; /* -------------------------------------------------------------------------- */ class MeshEventHandler { public: virtual ~MeshEventHandler() {}; /* ------------------------------------------------------------------------ */ /* Internal code */ /* ------------------------------------------------------------------------ */ public: inline void sendEvent(const NewNodesEvent & event) { onNodesAdded (event.getList()); } - inline void sendEvent(const RemovedNodesEvent & event) { onNodesRemoved(event.getList()); } + inline void sendEvent(const RemovedNodesEvent & event) { onNodesRemoved(event.getList(), + event.getNewNumbering()); } inline void sendEvent(const NewElementsEvent & event) { onElementsAdded (event.getList()); } - inline void sendEvent(const RemovedElementsEvent & event) { onElementsRemoved(event.getList()); } + inline void sendEvent(const RemovedElementsEvent & event) { onElementsRemoved(event.getList(), + event.getNewNumbering()); } /* ------------------------------------------------------------------------ */ /* Interface */ /* ------------------------------------------------------------------------ */ public: virtual void onNodesAdded (__attribute__((unused)) const Vector<UInt> & nodes_list) { } - virtual void onNodesRemoved(__attribute__((unused)) const Vector<UInt> & nodes_list) { } + virtual void onNodesRemoved(__attribute__((unused)) const Vector<UInt> & nodes_list, + __attribute__((unused)) const Vector<UInt> & new_numbering) { } + virtual void onElementsAdded (__attribute__((unused)) const Vector<Element> & elements_list) { } - virtual void onElementsRemoved(__attribute__((unused)) const Vector<Element> & elements_list) { } + virtual void onElementsRemoved(__attribute__((unused)) const Vector<Element> & elements_list, + __attribute__((unused)) const ByElementTypeUInt & new_numbering) { } }; /* -------------------------------------------------------------------------- */ /* Mesh */ /* -------------------------------------------------------------------------- */ /** * @class Mesh this contain the coordinates of the nodes in the Mesh.nodes * Vector, and the connectivity. The connectivity are stored in by element * types. * * To know all the element types present in a mesh you can get the * Mesh::ConnectivityTypeList * * In order to loop on all element you have to loop on all types like this : * @code 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 Vector<UInt> & conn = mesh.getConnectivity(*it); for(UInt e = 0; e < nb_element; ++e) { ... } } @endcode */ class Mesh : protected Memory, public EventHandlerManager<MeshEventHandler> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// constructor that create nodes coordinates array Mesh(UInt spatial_dimension, 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 = "mesh", const MemoryID & memory_id = 0); /** * constructor that use an existing nodes coordinates * array, by getting the vector of coordinates */ Mesh(UInt spatial_dimension, Vector<Real> & nodes, const ID & id = "mesh", const MemoryID & memory_id = 0); virtual ~Mesh(); /// @typedef ConnectivityTypeList list of the types present in a Mesh typedef std::set<ElementType> ConnectivityTypeList; // typedef Vector<Real> * NormalsMap[_max_element_type]; private: /// initialize the connectivity to NULL and other stuff void init(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// function that computes the bounding box (fills xmin, xmax) void computeBoundingBox(); /// init a by-element-type real vector with provided ids template<typename T> void initByElementTypeVector(ByElementTypeVector<T> & v, UInt nb_component, - UInt size, + UInt spatial_dimension, const bool & flag_nb_node_per_elem_multiply = false, - ElementKind element_kind = _ek_regular) const; /// @todo: think about nicer way to do it + ElementKind element_kind = _ek_regular, + bool size_to_nb_element = false) const; /// @todo: think about nicer way to do it /// extract coordinates of nodes from an element template<typename T> inline void extractNodalValuesFromElement(const Vector<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); /// convert a linearized element to an element inline Element linearizedToElement (UInt linearized_element); /// update the types offsets array for the conversions inline void updateTypesOffsets(const GhostType & ghost_type); /// add a Vector of connectivity for the type <type>. inline void addConnectivityType(const ElementType & type); + /* ------------------------------------------------------------------------ */ + template <class Event> + inline void sendEvent(Event & event) { + if(event.getList().getSize() != 0) + EventHandlerManager<MeshEventHandler>::sendEvent<Event>(event); + } + + /* ------------------------------------------------------------------------ */ + template<typename T> + inline void removeNodesFromVector(Vector<T> & vect, const Vector<UInt> & new_numbering); + + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(ID, id, const ID &); /// get the spatial dimension of the mesh = number of component of the coordinates AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the nodes Vector aka coordinates AKANTU_GET_MACRO(Nodes, *nodes, const Vector<Real> &); AKANTU_GET_MACRO_NOT_CONST(Nodes, *nodes, Vector<Real> &); /// get the number of nodes AKANTU_GET_MACRO(NbNodes, nodes->getSize(), UInt); /// get the Vector of global ids of the nodes (only used in parallel) AKANTU_GET_MACRO(GlobalNodesIds, *nodes_global_ids, const Vector<UInt> &); /// get the global id of a node inline UInt getNodeGlobalId(UInt local_id) const; /// get the global number of nodes inline UInt getNbGlobalNodes() const; /// get the nodes type Vector AKANTU_GET_MACRO(NodesType, *nodes_type, const Vector<Int> &); inline Int 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(XMin, lower_bounds[0], Real); AKANTU_GET_MACRO(YMin, lower_bounds[1], Real); AKANTU_GET_MACRO(ZMin, lower_bounds[2], Real); AKANTU_GET_MACRO(XMax, upper_bounds[0], Real); AKANTU_GET_MACRO(YMax, upper_bounds[1], Real); AKANTU_GET_MACRO(ZMax, upper_bounds[2], Real); inline void getLowerBounds(Real * lower) const; inline void getUpperBounds(Real * upper) const; inline void getLocalLowerBounds(Real * lower) const; inline void getLocalUpperBounds(Real * upper) const; /// get the number of surfaces AKANTU_GET_MACRO(NbSurfaces, nb_surfaces, UInt); /// get the connectivity Vector for a given type AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Connectivity, connectivities, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Connectivity, connectivities, UInt); /// @todo take out this set, if mesh can read surface id /// set the number of surfaces AKANTU_SET_MACRO(NbSurfaces, nb_surfaces, 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 ghost element of a type in the mesh // inline UInt getNbGhostElement(const ElementType & type) 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; /// get the element connected to a subelement AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementToSubelement, element_to_subelement, Vector<Element>); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementToSubelement, element_to_subelement, Vector<Element>); /// get the subelement connected to an element AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(SubelementToElement, subelement_to_element, Element); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(SubelementToElement, subelement_to_element, Element); /// get the surface values of facets AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(SurfaceID, surface_id, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(SurfaceID, surface_id, UInt); /// set the int data to the surface id vectors void setSurfaceIDsFromIntData(const std::string & data_name); inline const Vector<UInt> & getUIntData(const ElementType & el_type, const std::string & data_name, const GhostType & ghost_type = _not_ghost) const; /* ------------------------------------------------------------------------ */ /* 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 local connectivity of a facet for a given facet type static inline UInt ** getFacetLocalConnectivity(const ElementType & type); /// get the type of the surface element associated to a given element static inline ElementType getFacetElementType(const ElementType & type); /// get the pointer to the list of elements for a given type inline Vector<UInt> * getReversedElementsPBCPointer(const ElementType & type); /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ typedef ByElementTypeUInt::type_iterator type_iterator; inline type_iterator firstType(UInt dim = 0, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.firstType(dim, ghost_type, kind); } inline type_iterator lastType(UInt dim = 0, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.lastType(dim, ghost_type, kind); } /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshIOMSH; friend class MeshIOMSHStruct; friend class MeshIODiana; friend class MeshUtils; friend class DistributedSynchronizer; AKANTU_GET_MACRO(NodesPointer, nodes, Vector<Real> *); /// get a pointer to the nodes_global_ids Vector<UInt> and create it if necessary inline Vector<UInt> * getNodesGlobalIdsPointer(); /// get a pointer to the nodes_type Vector<Int> and create it if necessary inline Vector<Int> * getNodesTypePointer(); /// get a pointer to the connectivity Vector for the given type and create it if necessary inline Vector<UInt> * getConnectivityPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); // inline Vector<Real> * getNormalsPointer(ElementType type) const; /// get a pointer to the surface_id Vector for the given type and create it if necessary inline Vector<UInt> * getSurfaceIDPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get the UIntDataMap for a given ElementType inline UIntDataMap & getUIntDataMap(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get the IntDataMap pointer (modifyable) for a given ElementType inline Vector<UInt> * getUIntDataPointer(const ElementType & el_type, const std::string & data_name, const GhostType & ghost_type = _not_ghost); /// get a pointer to the element_to_subelement Vector for the given type and create it if necessary inline Vector<Vector<Element> > * getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get a pointer to the subelement_to_element Vector for the given type and create it if necessary inline Vector<Element > * getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// id of the mesh ID id; /// array of the nodes coordinates Vector<Real> * nodes; /// global node ids Vector<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 Vector<Int> * nodes_type; /// global number of nodes; UInt nb_global_nodes; /// boolean to know if the nodes have to be deleted with the mesh or not bool created_nodes; /// all class of elements present in this mesh (for heterogenous meshes) ByElementTypeUInt connectivities; /// map to normals for all class of elements present in this mesh ByElementTypeReal normals; /// list of all existing types in the mesh ConnectivityTypeList type_set; /// the spatial dimension of this mesh UInt spatial_dimension; /// types offsets Vector<UInt> types_offsets; /// list of all existing types in the mesh ConnectivityTypeList ghost_type_set; /// ghost types offsets Vector<UInt> ghost_types_offsets; /// number of surfaces present in this mesh UInt nb_surfaces; /// surface id of the surface elements in this mesh ByElementTypeUInt surface_id; /// min of coordinates Real lower_bounds[3]; /// max of coordinates Real upper_bounds[3]; /// size covered by the mesh on each direction Real size[3]; /// local min of coordinates Real local_lower_bounds[3]; /// local max of coordinates Real local_upper_bounds[3]; /// List of elements connected to subelements ByElementTypeVector<Vector<Element> > element_to_subelement; /// List of subelements connected to elements ByElementTypeVector<Element > subelement_to_element; // /// list of elements that are reversed due to pbc // ByElementTypeUInt reversed_elements_pbc; // /// direction in which pbc are to be applied // UInt pbc_directions[3]; /// list of the vectors corresponding to tags in the mesh ByElementTypeUIntDataMap uint_data; }; /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Element & _this) { _this.printself(stream); return stream; } #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "mesh_inline_impl.cc" #endif #include "by_element_type_tmpl.hh" /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Mesh & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_MESH_HH__ */ diff --git a/src/fem/mesh_inline_impl.cc b/src/fem/mesh_inline_impl.cc index 58d315757..d84f56819 100644 --- a/src/fem/mesh_inline_impl.cc +++ b/src/fem/mesh_inline_impl.cc @@ -1,496 +1,550 @@ /** * @file mesh_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Wed Jul 14 23:58:08 2010 * * @brief Implementation of the inline functions of the mesh class * * @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/>. * */ __END_AKANTU__ #include "cohesive_element.hh" __BEGIN_AKANTU__ +/* -------------------------------------------------------------------------- */ +inline RemovedNodesEvent::RemovedNodesEvent(const Mesh & mesh) : + new_numbering(mesh.getNbNodes(), 1, "new_numbering") { +} + +/* -------------------------------------------------------------------------- */ +inline RemovedElementsEvent::RemovedElementsEvent(const Mesh & mesh) : + new_numbering("new_numbering", mesh.getID()) { +} + +/* -------------------------------------------------------------------------- */ +template <> +inline void Mesh::sendEvent<RemovedElementsEvent>(RemovedElementsEvent & event) { + if(event.getList().getSize() != 0) { + connectivities.onElementsRemoved(event.getNewNumbering()); + EventHandlerManager<MeshEventHandler>::sendEvent(event); + } +} + +/* -------------------------------------------------------------------------- */ +template <> +inline void Mesh::sendEvent<RemovedNodesEvent>(RemovedNodesEvent & event) { + if(event.getList().getSize() != 0) { + if(created_nodes) removeNodesFromVector(*nodes , event.getNewNumbering()); + if(nodes_global_ids) removeNodesFromVector(*nodes_global_ids, event.getNewNumbering()); + if(nodes_type) removeNodesFromVector(*nodes_type , event.getNewNumbering()); + + EventHandlerManager<MeshEventHandler>::sendEvent(event); + } +} + +/* -------------------------------------------------------------------------- */ +template<typename T> +inline void Mesh::removeNodesFromVector(Vector<T> & vect, const Vector<UInt> & new_numbering) { + Vector<T> tmp(vect.getSize(), vect.getNbComponent()); + UInt nb_component = vect.getNbComponent(); + UInt new_nb_nodes = 0; + for (UInt i = 0; i < new_numbering.getSize(); ++i) { + UInt new_i = new_numbering(i); + if(new_i != UInt(-1)) { + memcpy(tmp.storage() + new_i * nb_component, + vect.storage() + i * nb_component, + nb_component * sizeof(T)); + ++new_nb_nodes; + } + } + + tmp.resize(new_nb_nodes); + vect.copy(tmp); +} + /* -------------------------------------------------------------------------- */ inline UInt Mesh::elementToLinearized(const Element & elem) { AKANTU_DEBUG_ASSERT(elem.type < _max_element_type && elem.element < types_offsets.values[elem.type+1], "The element " << elem << "does not exists in the mesh " << id); return types_offsets.values[elem.type] + elem.element; } /* -------------------------------------------------------------------------- */ inline Element Mesh::linearizedToElement (UInt linearized_element) { UInt t; for (t = _not_defined; t != _max_element_type && linearized_element >= types_offsets(t); ++t); AKANTU_DEBUG_ASSERT(t != _max_element_type, "The linearized element " << linearized_element << "does not exists in the mesh " << id); --t; return Element(ElementType(t), linearized_element - types_offsets.values[t]); } /* -------------------------------------------------------------------------- */ inline void Mesh::updateTypesOffsets(const GhostType & ghost_type) { types_offsets.clear(); type_iterator it = firstType(0, ghost_type); type_iterator last = lastType(0, ghost_type); for (; it != last; ++it) types_offsets(*it) = connectivities(*it, ghost_type).getSize(); for (UInt t = _not_defined + 1; t < _max_element_type; ++t) types_offsets(t) += types_offsets(t - 1); for (UInt t = _max_element_type; t > _not_defined; --t) types_offsets(t) = types_offsets(t - 1); types_offsets(0) = 0; } /* -------------------------------------------------------------------------- */ inline const Mesh::ConnectivityTypeList & Mesh::getConnectivityTypeList(const GhostType & ghost_type) const { if (ghost_type == _not_ghost) return type_set; else return ghost_type_set; } /* -------------------------------------------------------------------------- */ inline Vector<UInt> * Mesh::getNodesGlobalIdsPointer() { AKANTU_DEBUG_IN(); if(nodes_global_ids == NULL) { std::stringstream sstr; sstr << id << ":nodes_global_ids"; nodes_global_ids = &(alloc<UInt>(sstr.str(), nodes->getSize(), 1)); } AKANTU_DEBUG_OUT(); return nodes_global_ids; } /* -------------------------------------------------------------------------- */ inline Vector<Int> * Mesh::getNodesTypePointer() { AKANTU_DEBUG_IN(); if(nodes_type == NULL) { std::stringstream sstr; sstr << id << ":nodes_type"; nodes_type = &(alloc<Int>(sstr.str(), nodes->getSize(), 1, -1)); } AKANTU_DEBUG_OUT(); return nodes_type; } /* -------------------------------------------------------------------------- */ inline Vector<UInt> * Mesh::getConnectivityPointer(const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Vector<UInt> * tmp; if(!connectivities.exists(type, ghost_type)) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); tmp = &(connectivities.alloc(0, nb_nodes_per_element, type, ghost_type)); AKANTU_DEBUG_INFO("The connectivity vector for the type " << type << " created"); if (ghost_type == _not_ghost) type_set.insert(type); else ghost_type_set.insert(type); updateTypesOffsets(ghost_type); } else { tmp = &connectivities(type, ghost_type); } AKANTU_DEBUG_OUT(); return tmp; } /* -------------------------------------------------------------------------- */ inline Vector<UInt> * Mesh::getSurfaceIDPointer(const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Vector<UInt> * tmp; if(!surface_id.exists(type, ghost_type)) { tmp = &(surface_id.alloc(0, 1, type, ghost_type)); AKANTU_DEBUG_INFO("The surface id vector for the type " << type << " created"); } else { tmp = &(surface_id(type, ghost_type)); } AKANTU_DEBUG_OUT(); return tmp; } /* -------------------------------------------------------------------------- */ inline Vector<Vector<Element> > * Mesh::getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Vector<Vector<Element> > * tmp; if(!element_to_subelement.exists(type, ghost_type)) { tmp = &(element_to_subelement.alloc(0, 1, type, ghost_type)); AKANTU_DEBUG_INFO("The element_to_subelement vector for the type " << type << " created"); } else { tmp = &(element_to_subelement(type, ghost_type)); } AKANTU_DEBUG_OUT(); return tmp; } /* -------------------------------------------------------------------------- */ inline Vector<Element > * Mesh::getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Vector<Element > * tmp; if(!subelement_to_element.exists(type, ghost_type)) { UInt nb_facets = getNbFacetsPerElement(type); tmp = &(subelement_to_element.alloc(0, nb_facets, type, ghost_type)); AKANTU_DEBUG_INFO("The subelement_to_element vector for the type " << type << " created"); } else { tmp = &(subelement_to_element(type, ghost_type)); } AKANTU_DEBUG_OUT(); return tmp; } /* -------------------------------------------------------------------------- */ inline Vector<UInt> * Mesh::getUIntDataPointer(const ElementType & el_type, const std::string & data_name, const GhostType & ghost_type) { // AKANTU_DEBUG_IN(); Vector<UInt> * data; // if(!uint_data.exists(el_type, ghost_type)){ // uint_data(UIntDataMap(), el_type, ghost_type); // } UIntDataMap & map = uint_data(el_type, ghost_type); UIntDataMap::iterator it = map.find(data_name); if(it == map.end()) { data = new Vector<UInt>(0, 1, data_name); map[data_name] = data; } else { data = it->second; } // AKANTU_DEBUG_OUT(); return data; } /* -------------------------------------------------------------------------- */ inline const Vector<UInt> & Mesh::getUIntData(const ElementType & el_type, const std::string & data_name, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); const UIntDataMap & map = uint_data(el_type, ghost_type); UIntDataMap::const_iterator it = map.find(data_name); AKANTU_DEBUG_ASSERT(it != map.end(), "No data named " << data_name << " in the mesh " << id); AKANTU_DEBUG_OUT(); return *(it->second); } /* -------------------------------------------------------------------------- */ inline UIntDataMap & Mesh::getUIntDataMap(const ElementType & el_type, const GhostType & ghost_type) { // AKANTU_DEBUG_ASSERT(uint_data.exists(el_type, ghost_type), // "No UIntDataMap for the type (" << ghost_type << ":" << el_type << ")"); return uint_data(el_type, ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); - const ByElementTypeUInt & const_conn = connectivities; - - const Vector<UInt> & conn = const_conn(type, ghost_type); - AKANTU_DEBUG_OUT(); - return conn.getSize(); + try { + const Vector<UInt> & conn = connectivities(type, ghost_type); + AKANTU_DEBUG_OUT(); + return conn.getSize(); + } catch (...) { + AKANTU_DEBUG_OUT(); + return 0; + } } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type) const { AKANTU_DEBUG_IN(); UInt * conn_val = getConnectivity(type, ghost_type).values; UInt nb_nodes_per_element = getNbNodesPerElement(type); Real local_coord[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); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElement(const ElementType & type) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = 0; #define GET_NB_NODES_PER_ELEMENT(type) \ nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement() #define GET_NB_NODES_PER_ELEMENT_COHESIVE(type) \ nb_nodes_per_element = CohesiveElement<type>::getNbNodesPerElement() AKANTU_BOOST_ELEMENT_SWITCH(GET_NB_NODES_PER_ELEMENT, AKANTU_REGULAR_ELEMENT_TYPE, GET_NB_NODES_PER_ELEMENT_COHESIVE, AKANTU_COHESIVE_ELEMENT_TYPE); #undef GET_NB_NODES_PER_ELEMENT #undef GET_NB_NODES_PER_ELEMENT_COHESIVE AKANTU_DEBUG_OUT(); return nb_nodes_per_element; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getP1ElementType(const ElementType & type) { AKANTU_DEBUG_IN(); ElementType element_p1 = _not_defined; #define GET_ELEMENT_P1(type) \ element_p1 = ElementClass<type>::getP1ElementType() AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(GET_ELEMENT_P1); #undef GET_NB_NODES_PER_ELEMENT_P1 AKANTU_DEBUG_OUT(); return element_p1; } /* -------------------------------------------------------------------------- */ inline ElementKind Mesh::getKind(const ElementType & type) { AKANTU_DEBUG_IN(); ElementKind kind = _ek_not_defined; #define GET_KIND(type) \ kind = ElementClass<type>::getKind() AKANTU_BOOST_ELEMENT_SWITCH(GET_KIND, AKANTU_REGULAR_ELEMENT_TYPE, GET_KIND, AKANTU_COHESIVE_ELEMENT_TYPE); #undef GET_KIND AKANTU_DEBUG_OUT(); return kind; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getSpatialDimension(const ElementType & type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = 0; #define GET_SPATIAL_DIMENSION(type) \ spatial_dimension = ElementClass<type>::getSpatialDimension() #define GET_SPATIAL_DIMENSION_COHESIVE(type) \ spatial_dimension = CohesiveElement<type>::getSpatialDimension() AKANTU_BOOST_ELEMENT_SWITCH(GET_SPATIAL_DIMENSION, AKANTU_REGULAR_ELEMENT_TYPE, GET_SPATIAL_DIMENSION_COHESIVE, AKANTU_COHESIVE_ELEMENT_TYPE); #undef GET_SPATIAL_DIMENSION #undef GET_SPATIAL_DIMENSION_COHESIVE AKANTU_DEBUG_OUT(); return spatial_dimension; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getFacetElementType(const ElementType & type) { AKANTU_DEBUG_IN(); ElementType surface_type = _not_defined; #define GET_FACET_TYPE(type) \ surface_type = ElementClass<type>::getFacetElementType() #define GET_FACET_TYPE_COHESIVE(type) \ surface_type = CohesiveElement<type>::getFacetElementType() AKANTU_BOOST_ELEMENT_SWITCH(GET_FACET_TYPE, AKANTU_REGULAR_ELEMENT_TYPE, GET_FACET_TYPE_COHESIVE, AKANTU_COHESIVE_ELEMENT_TYPE); #undef GET_FACET_TYPE #undef GET_FACET_TYPE_COHESIVE AKANTU_DEBUG_OUT(); return surface_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() #define GET_NB_FACET_COHESIVE(type) \ n_facet = CohesiveElement<type>::getNbFacetsPerElement() AKANTU_BOOST_ELEMENT_SWITCH(GET_NB_FACET, AKANTU_REGULAR_ELEMENT_TYPE, GET_NB_FACET_COHESIVE, AKANTU_COHESIVE_ELEMENT_TYPE); #undef GET_NB_FACET #undef GET_NB_FACET_COHESIVE AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline UInt ** Mesh::getFacetLocalConnectivity(const ElementType & type) { AKANTU_DEBUG_IN(); UInt ** facet_conn = NULL; #define GET_FACET_CON(type) \ facet_conn = ElementClass<type>::getFacetLocalConnectivityPerElement() #define GET_FACET_CON_COHESIVE(type) \ facet_conn = CohesiveElement<type>::getFacetLocalConnectivityPerElement() AKANTU_BOOST_ELEMENT_SWITCH(GET_FACET_CON, AKANTU_REGULAR_ELEMENT_TYPE, GET_FACET_CON_COHESIVE, AKANTU_COHESIVE_ELEMENT_TYPE); #undef GET_FACET_CON #undef GET_FACET_CON_COHESIVE AKANTU_DEBUG_OUT(); return facet_conn; } /* -------------------------------------------------------------------------- */ template<typename T> inline void Mesh::extractNodalValuesFromElement(const Vector<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)); } } /* -------------------------------------------------------------------------- */ #define DECLARE_GET_BOUND(Var, var) \ inline void Mesh::get##Var##Bounds(Real * var) const { \ for (UInt i = 0; i < spatial_dimension; ++i) { \ var[i] = var##_bounds[i]; \ } \ } \ DECLARE_GET_BOUND(Lower, lower) DECLARE_GET_BOUND(Upper, upper) DECLARE_GET_BOUND(LocalLower, local_lower) DECLARE_GET_BOUND(LocalUpper, local_upper) #undef DECLARE_GET_BOUND /* -------------------------------------------------------------------------- */ inline void Mesh::addConnectivityType(const ElementType & type){ getConnectivityPointer(type); } /* -------------------------------------------------------------------------- */ inline bool Mesh::isPureGhostNode(UInt n) const { return nodes_type ? (*nodes_type)(n) == -3 : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalOrMasterNode(UInt n) const { return nodes_type ? (*nodes_type)(n) == -2 || (*nodes_type)(n) == -1 : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalNode(UInt n) const { return nodes_type ? (*nodes_type)(n) == -1 : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isMasterNode(UInt n) const { return nodes_type ? (*nodes_type)(n) == -2 : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isSlaveNode(UInt n) const { return nodes_type ? (*nodes_type)(n) >= 0 : false; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeGlobalId(UInt local_id) const { return nodes_global_ids ? (*nodes_global_ids)(local_id) : local_id; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbGlobalNodes() const { return nodes_global_ids ? nb_global_nodes : nodes->getSize(); } /* -------------------------------------------------------------------------- */ inline Int Mesh::getNodeType(UInt local_id) const { return nodes_type ? (*nodes_type)(local_id) : -1; } diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 2801b7f48..f49e99176 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,906 +1,924 @@ /** * @file mesh_utils.cc * @author Guillaume ANCIAUX <guillaume.anciaux@epfl.ch> * @date Wed Aug 18 14:21:00 2010 * * @brief All mesh utils necessary for various tasks * * @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_utils.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<UInt> & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == 0) 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; UInt nb_nodes_per_element[nb_types]; // UInt nb_nodes_per_element_p1[nb_types]; UInt * conn_val[nb_types]; UInt nb_element[nb_types]; // ElementType type_p1; 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); // type_p1 = Mesh::getP1ElementType(type); // nb_nodes_per_element_p1[nb_good_types] = Mesh::getNbNodesPerElement(type_p1); conn_val[nb_good_types] = mesh.getConnectivity(type, _not_ghost).values; nb_element[nb_good_types] = mesh.getConnectivity(type, _not_ghost).getSize(); 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(); // node_offset.resize(nb_nodes + 1); // UInt * node_offset_val = node_offset.values; /// count number of occurrence of each node // memset(node_offset_val, 0, (nb_nodes + 1)*sizeof(UInt)); 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_offset_val[conn_val[t][el_offset + n]]++; } } } // /// convert the occurrence array in a csr one // for (UInt i = 1; i < nb_nodes; ++i) node_offset_val[i] += node_offset_val[i-1]; // for (UInt i = nb_nodes; i > 0; --i) node_offset_val[i] = node_offset_val[i-1]; // node_offset_val[0] = 0; node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// rearrange element to get the node-element list // node_to_elem.resize(node_offset_val[nb_nodes]); // UInt * node_to_elem_val = node_to_elem.values; 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_val[node_offset_val[conn_val[t][el_offset + n]]++] = linearized_el; } node_to_elem.endInsertions(); // for (UInt i = nb_nodes; i > 0; --i) node_offset_val[i] = node_offset_val[i-1]; // node_offset_val[0] = 0; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsByElementType(const Mesh & mesh, ElementType type, CSR<UInt> & node_to_elem) { // Vector<UInt> & node_offset, // Vector<UInt> & node_to_elem) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, _not_ghost).getSize(); UInt * conn_val = mesh.getConnectivity(type, _not_ghost).values; /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); // node_offset.resize(nb_nodes + 1); // UInt * node_offset_val = node_offset.values; // memset(node_offset_val, 0, (nb_nodes + 1)*sizeof(UInt)); /// 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]); // node_offset_val[conn_val[nb_nodes_per_element*el + n]]++; } /// convert the occurrence array in a csr one // for (UInt i = 1; i < nb_nodes; ++i) node_offset_val[i] += node_offset_val[i-1]; // for (UInt i = nb_nodes; i > 0; --i) node_offset_val[i] = node_offset_val[i-1]; // node_offset_val[0] = 0; node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list // node_to_elem.resize(node_offset_val[nb_nodes]); // UInt * node_to_elem_val = node_to_elem.values; 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_val[node_offset_val[conn_val[nb_nodes_per_element*el + n]]] = el; // node_offset_val[conn_val[nb_nodes_per_element*el + n]]++; } // /// rearrange node_offset to start with 0 // for (UInt i = nb_nodes; i > 0; --i) node_offset_val[i] = node_offset_val[i-1]; // node_offset_val[0] = 0; node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh){ AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); ByElementTypeReal barycenter; buildFacetsDimension(mesh, mesh, true, spatial_dimension, barycenter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); ByElementTypeReal barycenter; /// generate facets buildFacetsDimension(mesh, mesh_facets, false, spatial_dimension, barycenter); /// compute their barycenters mesh_facets.initByElementTypeVector(barycenter, spatial_dimension, spatial_dimension - 1); Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1); for(; it != end; ++it) { UInt nb_element = mesh_facets.getNbElement(*it); barycenter(*it).resize(nb_element); Vector<Real>::iterator<types::RVector> bary = barycenter(*it).begin(spatial_dimension); Vector<Real>::iterator<types::RVector> bary_end = barycenter(*it).end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { mesh_facets.getBarycenter(el, *it, bary->storage()); } } /// sort facets and generate subfacets for (UInt i = spatial_dimension - 1; i > 0; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i, barycenter); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension(Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, ByElementTypeReal & barycenter){ AKANTU_DEBUG_IN(); const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; UInt nb_types = type_list.size(); UInt nb_good_types = 0; UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element[nb_types]; UInt nb_nodes_per_facet[nb_types]; UInt nb_facets[nb_types]; UInt ** node_in_facet[nb_types]; Vector<UInt> * connectivity_facets[nb_types]; Vector<Vector<Element> > * element_to_subelement[nb_types]; Vector<Element> * subelement_to_element[nb_types]; UInt * conn_val[nb_types]; UInt nb_element[nb_types]; ElementType facet_type; Real epsilon = std::numeric_limits<Real>::epsilon(); for(it = type_list.begin(); it != type_list.end(); ++it) { ElementType type = *it; if(mesh.getSpatialDimension(type) != dimension) continue; nb_nodes_per_element[nb_good_types] = mesh.getNbNodesPerElement(type); facet_type = mesh.getFacetElementType(type); nb_facets[nb_good_types] = mesh.getNbFacetsPerElement(type); node_in_facet[nb_good_types] = mesh.getFacetLocalConnectivity(type); nb_nodes_per_facet[nb_good_types] = mesh.getNbNodesPerElement(facet_type); // getting connectivity of boundary facets connectivity_facets[nb_good_types] = mesh_facets.getConnectivityPointer(facet_type); connectivity_facets[nb_good_types]->resize(0); element_to_subelement[nb_good_types] = mesh_facets.getElementToSubelementPointer(facet_type); element_to_subelement[nb_good_types]->resize(0); conn_val[nb_good_types] = mesh.getConnectivity(type, _not_ghost).values; nb_element[nb_good_types] = mesh.getConnectivity(type, _not_ghost).getSize(); subelement_to_element[nb_good_types] = mesh_facets.getSubelementToElementPointer(type); subelement_to_element[nb_good_types]->resize(nb_element[nb_good_types]); nb_good_types++; } CSR<UInt> node_to_elem; // Vector<UInt> node_offset; // Vector<UInt> node_to_elem; // buildNode2Elements(mesh,node_offset,node_to_elem); buildNode2Elements(mesh, node_to_elem, dimension); // std::cout << "node offset " << std::endl << node_offset << std::endl; // std::cout << "node to elem " << std::endl << node_to_elem << std::endl; Vector<UInt> counter; /// count number of occurrence of each node 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 f = 0; f < nb_facets[t]; ++f) { //build the nodes involved in facet 'f' UInt facet_nodes[nb_nodes_per_facet[t]]; for (UInt n = 0; n < nb_nodes_per_facet[t]; ++n) { UInt node_facet = node_in_facet[t][f][n]; facet_nodes[n] = conn_val[t][el_offset + node_facet]; } //our reference is the first node CSR<UInt>::iterator first_node_elements; //UInt * first_node_elements = node_to_elem.values+node_offset.values[facet_nodes[0]]; UInt first_node_nelements = node_to_elem.getNbCols(facet_nodes[0]); // node_offset.values[facet_nodes[0]+1]- // node_offset.values[facet_nodes[0]]; counter.resize(first_node_nelements); 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 CSR<UInt>::iterator first_node_elements_end; first_node_elements_end = node_to_elem.end(facet_nodes[0]); for (UInt n = 1; n < nb_nodes_per_facet[t]; ++n) { CSR<UInt>::iterator node_elements, node_elements_begin, node_elements_end; node_elements_begin = node_to_elem.begin(facet_nodes[n]); node_elements_end = node_to_elem.end(facet_nodes[n]); // UInt * node_elements = node_to_elem.values+node_offset.values[facet_nodes[n]]; // node_offset.values[facet_nodes[n]+1]- // node_offset.values[facet_nodes[n]]; UInt local_el = 0; for (first_node_elements = node_to_elem.begin(facet_nodes[0]); first_node_elements != first_node_elements_end; ++first_node_elements, ++local_el) { for (node_elements = node_elements_begin; node_elements != node_elements_end; ++node_elements) { if (*first_node_elements == *node_elements) { ++counter.values[local_el]; // it may cause trouble: break; } } // if (counter.values[local_el] == nb_nodes_per_facet[t]) break; } } // bool connected_facet = false; //the connected elements are those for which counter is n_facet // UInt connected_element = -1; // 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; UInt minimum_el_index = std::numeric_limits<UInt>::max(); Vector<UInt> connected_elements; for (UInt el1 = 0; el1 < counter.getSize(); el1++) { UInt el_index = node_to_elem(facet_nodes[0], el1); if (counter.values[el1] == nb_nodes_per_facet[t]-1) { ++nb_element_connected_to_facet; minimum_el_index = std::min(minimum_el_index, el_index); connected_elements.push_back(el_index); } } if (minimum_el_index == linearized_el) { if (!boundary_only || (boundary_only && nb_element_connected_to_facet == 1)) { connectivity_facets[t]->push_back(facet_nodes); UInt current_nb_facets = element_to_subelement[t]->getSize(); element_to_subelement[t]->resize(current_nb_facets + 1); Vector<Element> & elements = (*element_to_subelement[t])(current_nb_facets); // 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(mesh.linearizedToElement(linearized_el)); /// boundary facet if (nb_element_connected_to_facet == 1) elements.push_back(ElementNull); /// internal facet else if (nb_element_connected_to_facet == 2) elements.push_back(mesh.linearizedToElement(connected_elements.values[1])); /// facet of facet else { UInt nb_connected = connected_elements.getSize(); for (UInt i = 1; i < nb_connected; ++i) { elements.push_back(mesh.linearizedToElement(connected_elements.values[i])); } /// check if sorting is needed: /// - in 3D to sort triangles around segments /// - in 2D to sort segments around points if (dimension == spatial_dimension - 1) { /// barycentrical coordinates for each connected /// element with respect to start_node Vector<Real> connected_nodes(nb_connected, 2); const Vector<Real> & coord = mesh_facets.getNodes(); const Vector<UInt> & facet_conn = mesh_facets.getConnectivity(facet_type); /// node around which the sorting is carried out is /// the first node of the current facet UInt start_node = facet_conn(facet_conn.getSize()-1, 0); Real start_coord[spatial_dimension]; for (UInt dim = 0; dim < spatial_dimension; ++dim) { start_coord[dim] = coord(start_node, dim); } if (spatial_dimension == 3) { /// vector connecting facet first node to second Real tangent[spatial_dimension]; /// vector connecting facet first node and /// barycenter of elements(0) Real temp[spatial_dimension]; /// two normals to the segment facet to define the /// reference system Real normal1[spatial_dimension]; Real normal2[spatial_dimension]; Vector<Real> & bar = barycenter(elements(0).type); /// facet second node UInt second_node = facet_conn(facet_conn.getSize()-1, 1); /// construction of tangent and temp arrays for (UInt dim = 0; dim < spatial_dimension; ++dim) { Real x1, x2; x1 = coord(second_node, dim); x2 = bar(elements(0).element, dim); tangent[dim] = x1 - start_coord[dim]; temp[dim] = x2 - start_coord[dim]; } /// get normal1 and normal2 Math::normalize3(tangent); Math::vectorProduct3(tangent, temp, normal1); Math::normalize3(normal1); Math::vectorProduct3(tangent, normal1, normal2); for (UInt n = 0; n < nb_connected; ++n) { Real bary_coord[spatial_dimension]; Vector<Real> & bary = barycenter(elements(n).type); /// get the barycenter local coordinates for (UInt dim = 0; dim < spatial_dimension; ++dim) { bary_coord[dim] = bary(elements(n).element, dim) - start_coord[dim]; } /// project the barycenter coordinates on the two /// normals to have them on the same plane connected_nodes(n, 0) = Math::vectorDot(bary_coord, normal1, spatial_dimension); connected_nodes(n, 1) = Math::vectorDot(bary_coord, normal2, spatial_dimension); } } else if (spatial_dimension == 2) { for (UInt n = 0; n < nb_connected; ++n) { Vector<Real> & bary = barycenter(elements(n).type); /// get the barycenter local coordinates for (UInt dim = 0; dim < spatial_dimension; ++dim) { connected_nodes(n, dim) = bary(elements(n).element, dim) - start_coord[dim]; } } } /// associate to each element a real value based on /// atan2 function (check wikipedia) std::map<Element, Real, CompElementLess> atan2; for (UInt n = 0; n < nb_connected; ++n) { Real x = connected_nodes(n, 0); Real y = connected_nodes(n, 1); /// in order to avoid division by zero: if (std::abs(y) <= std::abs(y) * epsilon && x < 0) y = Math::getTolerance(); atan2[elements(n)] = y / (sqrt(x * x + y * y) + x); } /// sort elements according to their atan2 values ElementSorter sorter(atan2); std::sort(elements.storage(), elements.storage() + elements.getSize(), sorter); } } /// current facet index UInt current_facet = connectivity_facets[t]->getSize() - 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.getSize(); ++elem) { if (elements(elem).type != _not_defined) { for (UInt f_in = 0; f_in < nb_facets[t]; ++f_in) { if ((*subelement_to_element[t])(elements(elem).element, f_in).type == _not_defined) { (*subelement_to_element[t])(elements(elem).element, f_in).type = facet_type; (*subelement_to_element[t])(elements(elem).element, f_in).element = current_facet; break; } } } } } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ // void MeshUtils::buildNormals(Mesh & mesh,UInt spatial_dimension){ // AKANTU_DEBUG_IN(); // const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); // Mesh::ConnectivityTypeList::const_iterator it; // UInt nb_types = type_list.size(); // UInt nb_nodes_per_element[nb_types]; // UInt nb_nodes_per_element_p1[nb_types]; // UInt nb_good_types = 0; // Vector<UInt> * connectivity[nb_types]; // Vector<Real> * normals[nb_types]; // if (spatial_dimension == 0) spatial_dimension = mesh.getSpatialDimension(); // for(it = type_list.begin(); it != type_list.end(); ++it) { // ElementType type = *it; // ElementType type_p1 = mesh.getP1ElementType(type); // if(mesh.getSpatialDimension(type) != spatial_dimension) continue; // nb_nodes_per_element[nb_good_types] = mesh.getNbNodesPerElement(type); // nb_nodes_per_element_p1[nb_good_types] = mesh.getNbNodesPerElement(type_p1); // // getting connectivity // connectivity[nb_good_types] = mesh.getConnectivityPointer(type); // if (!connectivity[nb_good_types]) // AKANTU_DEBUG_ERROR("connectivity is not allocatted : this should probably not have happened"); // //getting array of normals // normals[nb_good_types] = mesh.getNormalsPointer(type); // if(normals[nb_good_types]) // normals[nb_good_types]->resize(0); // else // normals[nb_good_types] = &mesh.createNormals(type); // nb_good_types++; // } // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, UInt * local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Vector<UInt> & nodes_numbers) { AKANTU_DEBUG_IN(); nodes_numbers.resize(0); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map<UInt, UInt> renumbering_map; /// renumber the nodes renumberNodesInConnectivity(local_connectivities, (nb_local_element + nb_ghost_element)*nb_nodes_per_element, renumbering_map, nodes_numbers); renumbering_map.clear(); /// copy the renumbered connectivity to the right place Vector<UInt> * local_conn = mesh.getConnectivityPointer(type); local_conn->resize(nb_local_element); memcpy(local_conn->values, local_connectivities, nb_local_element * nb_nodes_per_element * sizeof(UInt)); Vector<UInt> * ghost_conn = mesh.getConnectivityPointer(type,_ghost); ghost_conn->resize(nb_ghost_element); memcpy(ghost_conn->values, local_connectivities + nb_local_element * nb_nodes_per_element, nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity(UInt * list_nodes, UInt nb_nodes, std::map<UInt, UInt> & renumbering_map, Vector<UInt> & nodes_numbers) { AKANTU_DEBUG_IN(); UInt * connectivity = list_nodes; 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; nodes_numbers.push_back(old_node); node = nodes_numbers.getSize() - 1; renumbering_map[old_node] = node; } else { node = it->second; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::purifyMesh(Mesh & mesh) { AKANTU_DEBUG_IN(); - + std::map<UInt, UInt> renumbering_map; Vector<UInt> node_numbers; for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; Mesh::type_iterator it = mesh.firstType(0, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(0, ghost_type, _ek_not_defined); for(; it != end; ++it) { ElementType type(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Vector<UInt> & connectivity_vect = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity_vect.getSize()); UInt * connectivity = connectivity_vect.storage(); renumberNodesInConnectivity (connectivity, nb_element*nb_nodes_per_element, renumbering_map, node_numbers); } } - UInt spatial_dimension = mesh.getSpatialDimension(); - Vector<Real> & nodes = const_cast<Vector<Real> &>(mesh.getNodes()); - Vector<Real>::iterator<types::RVector> nodes_it = nodes.begin(spatial_dimension); - Vector<Real> new_nodes(0, spatial_dimension); + + RemovedNodesEvent remove_nodes(mesh); + Vector<UInt> & nodes_removed = remove_nodes.getList(); + Vector<UInt> & new_numbering = remove_nodes.getNewNumbering(); + + std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); for (UInt i = 0; i < node_numbers.getSize(); ++i) { - new_nodes.push_back(nodes_it + node_numbers(i)); + new_numbering(node_numbers(i)) = i; + } + + for (UInt i = 0; i < new_numbering.getSize(); ++i) { + if(new_numbering(i) == UInt(-1)) + nodes_removed.push_back(i); } - std::copy(new_nodes.begin(spatial_dimension), new_nodes.end(spatial_dimension), - nodes.begin(spatial_dimension)); - - nodes.resize(node_numbers.getSize()); + mesh.sendEvent(remove_nodes); + + // UInt spatial_dimension = mesh.getSpatialDimension(); + // Vector<Real> & nodes = const_cast<Vector<Real> &>(mesh.getNodes()); + // Vector<Real>::iterator<types::RVector> nodes_it = nodes.begin(spatial_dimension); + // Vector<Real> new_nodes(0, spatial_dimension); + + // for (UInt i = 0; i < node_numbers.getSize(); ++i) { + // new_nodes.push_back(nodes_it + node_numbers(i)); + // } + + // std::copy(new_nodes.begin(spatial_dimension), new_nodes.end(spatial_dimension), + // nodes.begin(spatial_dimension)); + + // nodes.resize(node_numbers.getSize()); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::setUIntData(Mesh & mesh, UInt * data, UInt nb_tags, const ElementType & type) { AKANTU_DEBUG_IN(); UInt nb_element = mesh.getNbElement(type, _not_ghost); UInt nb_ghost_element = mesh.getNbElement(type, _ghost); char * names = reinterpret_cast<char *>(data + (nb_element + nb_ghost_element) * nb_tags); UIntDataMap & uint_data_map = mesh.getUIntDataMap(type, _not_ghost); UIntDataMap & ghost_uint_data_map = mesh.getUIntDataMap(type, _ghost); for (UInt t = 0; t < nb_tags; ++t) { std::string name(names); // std::cout << name << std::endl; names += name.size() + 1; UIntDataMap::iterator it = uint_data_map.find(name); if(it == uint_data_map.end()) { uint_data_map[name] = new Vector<UInt>(0, 1, name); it = uint_data_map.find(name); } it->second->resize(nb_element); memcpy(it->second->values, data, nb_element * sizeof(UInt)); data += nb_element; it = ghost_uint_data_map.find(name); if(it == ghost_uint_data_map.end()) { ghost_uint_data_map[name] = new Vector<UInt>(0, 1, name); it = ghost_uint_data_map.find(name); } it->second->resize(nb_ghost_element); memcpy(it->second->values, data, nb_ghost_element * sizeof(UInt)); data += nb_ghost_element; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildSurfaceID(Mesh & mesh) { AKANTU_DEBUG_IN(); // Vector<UInt> node_offset; // Vector<UInt> node_to_elem; CSR<UInt> node_to_elem; /// Get list of surface elements UInt spatial_dimension = mesh.getSpatialDimension(); // buildNode2Elements(mesh, node_offset, node_to_elem, spatial_dimension-1); buildNode2Elements(mesh, node_to_elem, spatial_dimension-1); /// Find which types of elements have been linearized const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; UInt nb_types = type_list.size(); ElementType lin_element_type[nb_types]; UInt nb_lin_types = 0; UInt nb_nodes_per_element[nb_types]; UInt nb_nodes_per_element_p1[nb_types]; UInt * conn_val[nb_types]; UInt nb_element[nb_types+1]; ElementType type_p1; for(it = type_list.begin(); it != type_list.end(); ++it) { ElementType type = *it; if(Mesh::getSpatialDimension(type) != spatial_dimension) continue; ElementType facet_type = mesh.getFacetElementType(type); lin_element_type[nb_lin_types] = facet_type; nb_nodes_per_element[nb_lin_types] = Mesh::getNbNodesPerElement(facet_type); type_p1 = Mesh::getP1ElementType(facet_type); nb_nodes_per_element_p1[nb_lin_types] = Mesh::getNbNodesPerElement(type_p1); conn_val[nb_lin_types] = mesh.getConnectivity(facet_type, _not_ghost).values; nb_element[nb_lin_types] = mesh.getNbElement(facet_type, _not_ghost); nb_lin_types++; } for (UInt i = 1; i < nb_lin_types; ++i) nb_element[i] += nb_element[i+1]; for (UInt i = nb_lin_types; i > 0; --i) nb_element[i] = nb_element[i-1]; nb_element[0] = 0; /// Find close surfaces Vector<Int> surface_value_id(1, nb_element[nb_lin_types], -1); Int * surf_val = surface_value_id.values; UInt nb_surfaces = 0; UInt nb_cecked_elements; UInt nb_elements_to_ceck; UInt * elements_to_ceck = new UInt [nb_element[nb_lin_types]]; memset(elements_to_ceck, 0, nb_element[nb_lin_types]*sizeof(UInt)); for (UInt lin_el = 0; lin_el < nb_element[nb_lin_types]; ++lin_el) { if(surf_val[lin_el] != -1) continue; /* Surface id already assigned */ /* First element of new surface */ surf_val[lin_el] = nb_surfaces; nb_cecked_elements = 0; nb_elements_to_ceck = 1; memset(elements_to_ceck, 0, nb_element[nb_lin_types]*sizeof(UInt)); elements_to_ceck[0] = lin_el; // Find others elements belonging to this surface while(nb_cecked_elements < nb_elements_to_ceck) { UInt ceck_lin_el = elements_to_ceck[nb_cecked_elements]; // Transform linearized index of element into ElementType one UInt lin_type_nb = 0; while (ceck_lin_el >= nb_element[lin_type_nb+1]) lin_type_nb++; UInt ceck_el = ceck_lin_el - nb_element[lin_type_nb]; // Get connected elements UInt el_offset = ceck_el*nb_nodes_per_element[lin_type_nb]; for (UInt n = 0; n < nb_nodes_per_element_p1[lin_type_nb]; ++n) { UInt node_id = conn_val[lin_type_nb][el_offset + n]; CSR<UInt>::iterator it_n; for (it_n = node_to_elem.begin(node_id); it_n != node_to_elem.end(node_id); ++it_n) { // for (UInt i = node_offset.values[node_id]; i < node_offset.values[node_id+1]; ++i) { if(surf_val[*it_n] == -1) { /* Found new surface element */ surf_val[*it_n] = nb_surfaces; elements_to_ceck[nb_elements_to_ceck] = *it_n; nb_elements_to_ceck++; } // if(surf_val[node_to_elem.values[i]] == -1) { /* Found new surface element */ // surf_val[node_to_elem.values[i]] = nb_surfaces; // elements_to_ceck[nb_elements_to_ceck] = node_to_elem.values[i]; // nb_elements_to_ceck++; // } } } nb_cecked_elements++; } nb_surfaces++; } delete [] elements_to_ceck; /// Transform local linearized element index in the global one for (UInt i = 0; i < nb_lin_types; ++i) nb_element[i] = nb_element[i+1] - nb_element[i]; UInt el_offset = 0; for (UInt type_it = 0; type_it < nb_lin_types; ++type_it) { ElementType type = lin_element_type[type_it]; Vector<UInt> * surf_id_type = mesh.getSurfaceIDPointer(type, _not_ghost); surf_id_type->resize(nb_element[type_it]); surf_id_type->clear(); for (UInt el = 0; el < nb_element[type_it]; ++el) surf_id_type->values[el] = surf_val[el+el_offset]; el_offset += nb_element[type_it]; } /// Set nb_surfaces in mesh mesh.nb_surfaces = nb_surfaces; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNodesPerSurface(const Mesh & mesh, CSR<UInt> & nodes_per_surface) { AKANTU_DEBUG_IN(); UInt nb_surfaces = mesh.getNbSurfaces(); UInt nb_nodes = mesh.getNbNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); //surface elements UInt nb_facet_types = 0; ElementType facet_type[_max_element_type]; Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator end = mesh.lastType(spatial_dimension); for(; it != end; ++it) { facet_type[nb_facet_types++] = mesh.getFacetElementType(*it); } UInt * surface_nodes_id = new UInt[nb_nodes*nb_surfaces]; std::fill_n(surface_nodes_id, nb_surfaces*nb_nodes, 0); for(UInt t = 0; t < nb_facet_types; ++t) { ElementType type = facet_type[t]; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt * connecticity = mesh.getConnectivity(type, _not_ghost).values; UInt * surface_id = mesh.getSurfaceID(type, _not_ghost).values;; for (UInt el = 0; el < nb_element; ++el) { UInt offset = *surface_id * nb_nodes; for (UInt n = 0; n < nb_nodes_per_element; ++n) { surface_nodes_id[offset + *connecticity] = 1; ++connecticity; } ++surface_id; } } nodes_per_surface.resizeRows(nb_surfaces); nodes_per_surface.clearRows(); UInt * surface_nodes_id_tmp = surface_nodes_id; for (UInt s = 0; s < nb_surfaces; ++s) for (UInt n = 0; n < nb_nodes; ++n) nodes_per_surface.rowOffset(s) += *surface_nodes_id_tmp++; nodes_per_surface.countToCSR(); nodes_per_surface.resizeCols(); nodes_per_surface.beginInsertions(); surface_nodes_id_tmp = surface_nodes_id; for (UInt s = 0; s < nb_surfaces; ++s) for (UInt n = 0; n < nb_nodes; ++n) { if (*surface_nodes_id_tmp == 1) nodes_per_surface.insertInRow(s, n); surface_nodes_id_tmp++; } nodes_per_surface.endInsertions(); delete [] surface_nodes_id; AKANTU_DEBUG_OUT(); } __END_AKANTU__ // LocalWords: ElementType diff --git a/src/model/solid_mechanics/contact/contact_rigid.cc b/src/model/solid_mechanics/contact/contact_rigid.cc index 86947f32c..55239c4f4 100644 --- a/src/model/solid_mechanics/contact/contact_rigid.cc +++ b/src/model/solid_mechanics/contact/contact_rigid.cc @@ -1,1221 +1,1221 @@ /** * @file contact_rigid.cc * @author David Kammer <david.kammer@epfl.ch> * @date Tue Oct 26 17:15:08 2010 * * @brief Specialization of the contact structure for 3d contact in explicit * time scheme * * @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 "contact_rigid.hh" #include "contact_search.hh" /* -------------------------------------------------------------------------- */ #include <iostream> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ ContactRigid::ImpactorInformationPerMaster::ImpactorInformationPerMaster(const Surface master_id, const UInt spatial_dimension) : master_id(master_id) { AKANTU_DEBUG_IN(); this->impactor_surfaces = new std::vector<Surface>(0); this->active_impactor_nodes = new Vector<UInt>(0,1); //this->master_element_offset = new Vector<UInt>(0,1); this->master_element_type = new std::vector<ElementType>(0); this->master_normals = new Vector<Real>(0, spatial_dimension); this->node_is_sticking = new Vector<bool>(0,2); this->friction_forces = new Vector<Real>(0,spatial_dimension); this->stick_positions = new Vector<Real>(0,spatial_dimension); this->residual_forces = new Vector<Real>(0,spatial_dimension); this->previous_velocities = new Vector<Real>(0,spatial_dimension); this->friction_resistances = new Vector<Real>(0); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ContactRigid::ImpactorInformationPerMaster::~ImpactorInformationPerMaster() { AKANTU_DEBUG_IN(); delete this->impactor_surfaces; delete this->active_impactor_nodes; // delete this->master_element_offset; delete this->master_element_type; delete this->master_normals; delete this->node_is_sticking; delete this->friction_forces; delete this->stick_positions; delete this->residual_forces; delete this->previous_velocities; delete this->friction_resistances; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ContactRigid::ContactRigid(const SolidMechanicsModel & model, const ContactType & type, const ContactID & id, const MemoryID & memory_id) : Contact(model, type, id, memory_id), spatial_dimension(model.getSpatialDimension()), mesh(model.getFEM().getMesh()), prakash(false), ref_velocity(0.), characterstic_length(0.) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ContactRigid::~ContactRigid() { AKANTU_DEBUG_IN(); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; for (it_imp = this->impactors_information.begin(); it_imp != this->impactors_information.end(); ++it_imp) { delete it_imp->second; } this->impactors_information.clear(); this->friction_coefficient.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::addMasterSurface(const Surface & master_surface) { AKANTU_DEBUG_IN(); Contact::addMasterSurface(master_surface); ImpactorInformationPerMaster * impactor_info = new ImpactorInformationPerMaster(master_surface, this->spatial_dimension); this->impactors_information[master_surface] = impactor_info; //this->friction_coefficient[master_surface] = NULL; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::addImpactorSurfaceToMasterSurface(const Surface & impactor_surface, const Surface & master_surface) { AKANTU_DEBUG_IN(); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master_surface); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master_surface << "couldn't be found and erased in impactors_information map"); it_imp->second->impactor_surfaces->push_back(impactor_surface); /* for (UInt m=0; m < this->impactors_information.size(); ++m) { if (this->impactors_information.at(m)->master_id == master_surface) { this->impactors_information.at(m)->impactor_surfaces->push_back(impactor_surface); break; } } */ ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master_surface); if (it_fc != this->friction_coefficient.end()) it_fc->second->addImpactorSurface(impactor_surface); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::removeMasterSurface(const Surface & master_surface) { AKANTU_DEBUG_IN(); Contact::removeMasterSurface(master_surface); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master_surface); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master_surface << "couldn't be found and erased in impactors_information map"); delete it_imp->second; this->impactors_information.erase(it_imp); ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master_surface); AKANTU_DEBUG_ASSERT(it_fc != this->friction_coefficient.end(), "The master surface: " << master_surface << "couldn't be found and erased in friction_coefficient map"); this->friction_coefficient.erase(it_fc); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::removeImpactorSurfaceFromMasterSurface(const Surface & impactor_surface, const Surface & master_surface) { AKANTU_DEBUG_IN(); // find in map the impactor information for the given master surface ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master_surface); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master_surface << "couldn't be found and erased in impactors_information map"); std::vector<Surface> * imp_surfaces = it_imp->second->impactor_surfaces; // find and delete the impactor surface std::vector<Surface>::iterator it_surf; it_surf = find(imp_surfaces->begin(), imp_surfaces->end(), impactor_surface); AKANTU_DEBUG_ASSERT(it_surf != imp_surfaces->end(), "Couldn't find impactor surface " << impactor_surface << " for the master surface " << master_surface << " and couldn't erase it"); imp_surfaces->erase(it_surf); /* for (UInt m=0; m < this->impactors_information.size(); ++m) { ImpactorInformationPerMaster * impactor_info = this->impactors_information.at(m); if (impactor_info->master_id == master_surface) { for (UInt i=0; i < impactor_info->impactor_surfaces->size(); ++i) { Surface imp_surface = impactor_info->impactor_surfaces->at(i); if (imp_surface == impactor_surface) { impactor_info->impactor_surfaces->erase(impactor_info->impactor_surfaces->begin()+i); break; } } } } */ ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master_surface); if (it_fc != this->friction_coefficient.end()) it_fc->second->removeImpactorSurface(impactor_surface); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::solveContact() { AKANTU_DEBUG_IN(); for(UInt m=0; m < master_surfaces.size(); ++m) { Surface master = this->master_surfaces.at(m); std::stringstream sstr; sstr << id << ":penetration_list"; PenetrationList * penet_list = new PenetrationList(sstr.str()); contact_search->findPenetration(master, *penet_list); solvePenetrationClosestProjection(master, *penet_list); delete penet_list; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /*void ContactRigid::solvePenetration(const PenetrationList & penet_list) { AKANTU_DEBUG_IN(); const UInt dim = ; const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; /// find existing surface element types UInt nb_types = type_list.size(); UInt nb_facet_types = 0; ElementType facet_type[_max_element_type]; for(it = type_list.begin(); it != type_list.end(); ++it) { ElementType type = *it; if(mesh.getSpatialDimension(type) == spatial_dimension) { ElementType current_facet_type = mesh.getFacetElementType(type); facet_type[nb_facet_types++] = current_facet_type; } } Real * current_position = model.getCurrentPosition().values; Real * displacement = model.getDisplacement().values; Real * increment = model.getIncrement().values; UInt * penetrating_nodes = penet_list.penetrating_nodes.values; for (UInt n=0; n < penet_list.penetrating_nodes.getSize(); ++n) { UInt current_node = penetrating_nodes[n]; // count number of elements penetrated by this node UInt nb_penetrated_facets = 0; ElementType penetrated_type; for (UInt el_type = 0; el_type < nb_facet_types; ++el_type) { ElementType type = facet_type[el_type]; UInt offset_min = penet_list.penetrated_facets_offset[type].get(n); UInt offset_max = penet_list.penetrated_facets_offset[type].get(n+1); nb_penetrated_facets += offset_max - offset_min; penetrated_type = type; } // easy case: node penetrated only one facet if(nb_penetrated_facets == 1) { Real * facets_normals = penet_list.facets_normals[penetrated_type].values; Real * gaps = penet_list.gaps[penetrated_type].values; Real * projected_positions = penet_list.projected_positions[penetrated_type].values; UInt offset_min = penet_list.penetrated_facets_offset[penetrated_type].get(n); for(UInt i=0; i < dim; ++i) { current_position[current_node*dim + i] = projected_positions[offset_min*dim + i]; Real displacement_correction = gaps[offset_min*dim + i] * normals[offset_min*dim + i]; displacement[current_node*dim + i] = displacement[current_node*dim + i] - displacement_correction; increment [current_node*dim + i] = increment [current_node*dim + i] - displacement_correction; } } // if more penetrated facets, find the one from which the impactor node is coming else { } } }*/ /* -------------------------------------------------------------------------- */ void ContactRigid::solvePenetrationClosestProjection(const Surface master, const PenetrationList & penet_list) { AKANTU_DEBUG_IN(); const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; /// find existing surface element types UInt nb_facet_types = 0; ElementType facet_type[_max_element_type]; for(it = type_list.begin(); it != type_list.end(); ++it) { ElementType type = *it; if(mesh.getSpatialDimension(type) == spatial_dimension) { ElementType current_facet_type = mesh.getFacetElementType(type); facet_type[nb_facet_types++] = current_facet_type; } } for (UInt n=0; n < penet_list.penetrating_nodes.getSize(); ++n) { // find facet for which the gap is the smallest Real min_gap = std::numeric_limits<Real>::max(); ElementType penetrated_type; UInt penetrated_facet_offset; for (UInt el_type = 0; el_type < nb_facet_types; ++el_type) { ElementType type = facet_type[el_type]; Real * gaps = penet_list.gaps(type, _not_ghost).storage(); UInt offset_min = penet_list.penetrated_facets_offset(type, _not_ghost)(n); UInt offset_max = penet_list.penetrated_facets_offset(type, _not_ghost)(n+1); for (UInt f = offset_min; f < offset_max; ++f) { if(gaps[f] < min_gap) { min_gap = gaps[f]; penetrated_type = type; penetrated_facet_offset = f; } } } bool is_active = isAlreadyActiveImpactor(master, penet_list, n, penetrated_type, penetrated_facet_offset); if (!is_active) { // correct the position of the impactor projectImpactor(penet_list, n, penetrated_type, penetrated_facet_offset); lockImpactorNode(master, penet_list, n, penetrated_type, penetrated_facet_offset); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool ContactRigid::isAlreadyActiveImpactor(const Surface master, const PenetrationList & penet_list, const UInt impactor_index, const ElementType facet_type, const UInt facet_offset) { AKANTU_DEBUG_IN(); bool is_active = false; UInt * penetrating_nodes = penet_list.penetrating_nodes.values; UInt impactor_node = penetrating_nodes[impactor_index]; // find facet normal Real * facets_normals = penet_list.facets_normals(facet_type, _not_ghost).storage(); Real * facet_normal = &facets_normals[facet_offset*spatial_dimension]; Int normal[this->spatial_dimension]; for(UInt i = 0; i < this->spatial_dimension; ++i) normal[i] = Int(floor(facet_normal[i] + 0.5)); // check if this is already in the active impactor node list ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; Vector<UInt> * active_nodes = impactor_info->active_impactor_nodes; Vector<Real> * master_normals = impactor_info->master_normals; for (UInt i=0; i<active_nodes->getSize(); ++i) { - if(active_nodes->at(i) == impactor_node) { + if((*active_nodes)(i) == impactor_node) { UInt count = 0; for (UInt d=0; d<this->spatial_dimension; ++d) { - if(Math::are_float_equal(master_normals->at(i,d),normal[d])) + if(Math::are_float_equal((*master_normals)(i,d),normal[d])) count++; } if(count == this->spatial_dimension) is_active = true; } } AKANTU_DEBUG_OUT(); return is_active; } /* -------------------------------------------------------------------------- */ void ContactRigid::projectImpactor(const PenetrationList & penet_list, const UInt impactor_index, const ElementType facet_type, const UInt facet_offset) { AKANTU_DEBUG_IN(); const bool increment_flag = model.getIncrementFlag(); UInt * penetrating_nodes = penet_list.penetrating_nodes.values; Real * facets_normals = penet_list.facets_normals(facet_type, _not_ghost).storage(); Real * gaps = penet_list.gaps(facet_type, _not_ghost).storage(); Real * projected_positions = penet_list.projected_positions(facet_type, _not_ghost).storage(); Real * current_position = model.getCurrentPosition().values; Real * displacement = model.getDisplacement().values; Real * increment = NULL; if(increment_flag) increment = model.getIncrement().values; UInt impactor_node = penetrating_nodes[impactor_index]; for(UInt i=0; i < this->spatial_dimension; ++i) { current_position[impactor_node*spatial_dimension + i] = projected_positions[facet_offset*spatial_dimension + i]; Real displacement_correction = gaps[facet_offset] * facets_normals[facet_offset*spatial_dimension + i]; displacement[impactor_node*spatial_dimension + i] = displacement[impactor_node*spatial_dimension + i] - displacement_correction; if(increment_flag) increment [impactor_node*spatial_dimension + i] = increment [impactor_node*spatial_dimension + i] - displacement_correction; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::lockImpactorNode(const Surface master, const PenetrationList & penet_list, const UInt impactor_index, const ElementType facet_type, const UInt facet_offset) { AKANTU_DEBUG_IN(); bool init_state_stick = true; // node is in sticking when it gets in contact UInt * penetrating_nodes = penet_list.penetrating_nodes.values; UInt impactor_node = penetrating_nodes[impactor_index]; Real * facets_normals = penet_list.facets_normals(facet_type, _not_ghost).storage(); Real * facet_normal = &facets_normals[facet_offset*spatial_dimension]; Real normal[this->spatial_dimension]; //Int * normal_val = &normal[0]; bool * bound_val = this->model.getBoundary().values; Real * position_val = this->model.getCurrentPosition().values; Real * veloc_val = this->model.getVelocity().values; Real * accel_val = this->model.getAcceleration().values; Real * residual_val = this->model.getResidual().values; for(UInt i = 0; i < this->spatial_dimension; ++i) normal[i] = floor(facet_normal[i] + 0.5); for(UInt i = 0; i < this->spatial_dimension; ++i) { UInt index = impactor_node * spatial_dimension + i; if(!Math::are_float_equal(normal[i],0)) { bound_val[index] = true; veloc_val[index] = 0.; accel_val[index] = 0.; } // if node is in initial stick its tangential velocity has to be zero if(init_state_stick) { veloc_val[index] = 0.; accel_val[index] = 0.; } } ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; impactor_info->active_impactor_nodes->push_back(impactor_node); // impactor_info->master_element_offset->push_back(facet_offset); impactor_info->master_element_type->push_back(facet_type); impactor_info->master_normals->push_back(normal); // initial value for stick state when getting in contact bool init_sticking[2]; if (init_state_stick) { init_sticking[0] = true; init_sticking[1] = true; } else { init_sticking[0] = false; init_sticking[1] = false; } impactor_info->node_is_sticking->push_back(init_sticking); Real init_friction_force[this->spatial_dimension]; for(UInt i=0; i<this->spatial_dimension; ++i) { init_friction_force[i] = 0.; } impactor_info->friction_forces->push_back(init_friction_force); impactor_info->stick_positions->push_back(&(position_val[impactor_node*this->spatial_dimension])); impactor_info->residual_forces->push_back(&(residual_val[impactor_node*this->spatial_dimension])); impactor_info->previous_velocities->push_back(&(veloc_val[impactor_node*this->spatial_dimension])); impactor_info->friction_resistances->push_back(0.); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::avoidAdhesion() { AKANTU_DEBUG_IN(); Real * residual_val = this->model.getResidual().values; bool * bound_val = this->model.getBoundary().values; for(UInt m=0; m < this->master_surfaces.size(); ++m) { Surface master = this->master_surfaces.at(m); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; for (UInt n=0; n < impactor_info->active_impactor_nodes->getSize(); ++n) { - UInt current_node = impactor_info->active_impactor_nodes->at(n); + UInt current_node = (*impactor_info->active_impactor_nodes)(n); for (UInt i=0; i < spatial_dimension; ++i) { - Int direction = Int(impactor_info->master_normals->at(n,i)); + Int direction = Int((*impactor_info->master_normals)(n,i)); Real force = residual_val[current_node * spatial_dimension + i]; if(force * direction > 0.) { bound_val[current_node * spatial_dimension + i] = false; impactor_info->active_impactor_nodes->erase(n); // impactor_info->master_element_offset->erase(n); impactor_info->master_element_type->erase(impactor_info->master_element_type->begin()+n); impactor_info->master_normals->erase(n); impactor_info->node_is_sticking->erase(n); impactor_info->friction_forces->erase(n); impactor_info->stick_positions->erase(n); impactor_info->residual_forces->erase(n); impactor_info->previous_velocities->erase(n); impactor_info->friction_resistances->erase(n); n--; break; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::frictionPredictor() { AKANTU_DEBUG_IN(); const Real null_tolerance = std::numeric_limits<Real>::epsilon() * 2.; Real * residual_val = this->model.getResidual().values; Real * acceleration_val = this->model.getAcceleration().values; Real * velocity_val = this->model.getVelocity().values; for(UInt m=0; m < this->master_surfaces.size(); ++m) { Surface master = this->master_surfaces.at(m); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master); AKANTU_DEBUG_ASSERT(it_fc != this->friction_coefficient.end(), "The master surface: " << master << "couldn't be found in friction_coefficient map"); FrictionCoefficient * fric_coef = it_fc->second; AKANTU_DEBUG_ASSERT(fric_coef != NULL, "There is no friction coefficient defined for master surface " << master); UInt nb_active_impactor_nodes = impactor_info->active_impactor_nodes->getSize(); // compute the friction coefficient for each active impactor node Vector<Real> friction_coefficient_values(nb_active_impactor_nodes, 1); Real * friction_coefficient_values_p = friction_coefficient_values.values; fric_coef->computeFrictionCoefficient(friction_coefficient_values); UInt * active_impactor_nodes_val = impactor_info->active_impactor_nodes->storage(); Real * direction_val = impactor_info->master_normals->storage(); bool * node_is_sticking_val = impactor_info->node_is_sticking->storage(); Real * friction_forces_val = impactor_info->friction_forces->storage(); Real * residual_forces_val = impactor_info->residual_forces->storage(); Real * previous_velocities_val = impactor_info->previous_velocities->storage(); Real * friction_resistances_val = impactor_info->friction_resistances->storage(); Vector<Real> & nodal_velocity = model.getVelocity(); for (UInt n=0; n < nb_active_impactor_nodes; ++n) { UInt current_node = active_impactor_nodes_val[n]; // save original residual for(UInt i=0; i < spatial_dimension; ++i) { residual_forces_val[n*spatial_dimension+i] = residual_val[current_node*spatial_dimension+i]; } // find friction force mu * normal force Real normal_contact_force = 0.; Real friction_force = 0.; for (UInt i=0; i < spatial_dimension; ++i) { if(!Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { normal_contact_force = std::abs(residual_val[current_node * this->spatial_dimension + i]); friction_force = friction_coefficient_values_p[n] * normal_contact_force; } } // prakash clifton regularization if (this->prakash) { // compute (|v| + v*)/L Real v_L_term = 0.; for (UInt i=0; i < spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) v_L_term += nodal_velocity(current_node,i) * nodal_velocity(current_node,i); } v_L_term = sqrt(v_L_term); v_L_term += this->ref_velocity; v_L_term /= this->characterstic_length; Real delta_t = this->model.getTimeStep(); // compute friction resistance friction_force *= v_L_term; friction_force += friction_resistances_val[n]/delta_t; friction_force /= (1/delta_t + v_L_term); } friction_resistances_val[n] = friction_force; // if node is sticking, friction force acts against the residual if (node_is_sticking_val[n*2]) { // compute length of projected residual Real projected_residual = 0.; for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { projected_residual += residual_val[current_node * this->spatial_dimension + i] * residual_val[current_node * this->spatial_dimension + i]; } } projected_residual = sqrt(projected_residual); // friction is weaker than residual -> start sliding if (friction_force < projected_residual) { node_is_sticking_val[n*2] = false; node_is_sticking_val[n*2+1] = false; // compute friction vector Real friction_direction[3]; for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { friction_direction[i] = residual_val[current_node * this->spatial_dimension + i]; friction_direction[i] /= projected_residual; } else friction_direction[i] = 0.; friction_direction[i] *= -1.; } // add friction force to residual for (UInt i=0; i < this->spatial_dimension; ++i) { Real directional_fric_force = friction_force * friction_direction[i]; friction_forces_val[n*this->spatial_dimension + i] = directional_fric_force; residual_val[current_node * this->spatial_dimension + i] += directional_fric_force; } } // friction is stronger than residual -> stay sticking else { // put residual in friction force and set residual to zero for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { friction_forces_val[n*spatial_dimension + i] = residual_val[current_node * this->spatial_dimension + i]; residual_val[current_node * this->spatial_dimension + i] = 0.; } else friction_forces_val[n*spatial_dimension + i] = 0.; friction_forces_val[n*spatial_dimension + i] *= -1.; } } } // end if stick // if node is sliding friction force acts against velocity and // in case there is no velocity it acts against the residual else { Real projected_residual = 0.; Real projected_velocity_magnitude = 0.; for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { projected_residual += residual_val[current_node * this->spatial_dimension + i] * residual_val[current_node * this->spatial_dimension + i]; projected_velocity_magnitude += previous_velocities_val[n * this->spatial_dimension + i] * previous_velocities_val[n * this->spatial_dimension + i]; } } projected_residual = sqrt(projected_residual); projected_velocity_magnitude = sqrt(projected_velocity_magnitude); // if no projected velocity nor friction force stronger than projected residual, this is stick if ((projected_velocity_magnitude < null_tolerance) && !(projected_residual > friction_force)) { // put residual in friction force and set residual to zero // set projected velocity and acceleration to zero for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { friction_forces_val[n*spatial_dimension + i] = residual_val[current_node * this->spatial_dimension + i]; residual_val [current_node * this->spatial_dimension + i] = 0.; velocity_val [current_node * this->spatial_dimension + i] = 0.; acceleration_val[current_node * this->spatial_dimension + i] = 0.; } else friction_forces_val[n*spatial_dimension + i] = 0.; friction_forces_val[n*spatial_dimension + i] *= -1.; } node_is_sticking_val[n*2] = true; node_is_sticking_val[n*2+1] = true; } // node is really sliding else { UInt index = 0; Real * direction_vector; Real direction_length; // if only velocity is zero (because slider just turned direction) if (projected_velocity_magnitude < null_tolerance) { index = current_node; direction_vector = residual_val; direction_length = projected_residual; } // there is velocity else { index = n; direction_vector = previous_velocities_val; direction_length = projected_velocity_magnitude; } // compute the friction direction Real friction_direction[3]; for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { friction_direction[i] = direction_vector[index * this->spatial_dimension + i]; friction_direction[i] /= direction_length; } else friction_direction[i] = 0.; friction_direction[i] *= -1.; } // add friction force to residual for (UInt i=0; i < this->spatial_dimension; ++i) { Real directional_fric_force = friction_force * friction_direction[i]; friction_forces_val[n*this->spatial_dimension + i] = directional_fric_force; residual_val[current_node * this->spatial_dimension + i] += directional_fric_force; } } } // end sliding } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::frictionCorrector() { AKANTU_DEBUG_IN(); const Real tolerance = std::numeric_limits<Real>::epsilon() * 100.; Real * residual_val = this->model.getResidual().values; Real * acceleration_val = this->model.getAcceleration().values; Real * velocity_val = this->model.getVelocity().values; Real time_step = this->model.getTimeStep(); for(UInt m=0; m < this->master_surfaces.size(); ++m) { Surface master = this->master_surfaces.at(m); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; UInt nb_active_impactor_nodes = impactor_info->active_impactor_nodes->getSize(); UInt * active_impactor_nodes_val = impactor_info->active_impactor_nodes->storage(); Real * direction_val = impactor_info->master_normals->storage(); bool * node_is_sticking_val = impactor_info->node_is_sticking->storage(); //Real * friction_forces_val = impactor_info->friction_forces->storage(); //Real * residual_forces_val = impactor_info->residual_forces->storage(); Real * previous_velocities_val = impactor_info->previous_velocities->storage(); for (UInt n=0; n < nb_active_impactor_nodes; ++n) { UInt current_node = active_impactor_nodes_val[n]; // check only sliding impactor nodes if (node_is_sticking_val[n*2]) continue; // compute scalar product of previous velocity with current velocity Real dot_prod_velocities = 0.; Real dot_prod_pred_velocities = 0.; Real current_proj_vel_mag = 0.; for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { dot_prod_velocities += velocity_val[current_node * this->spatial_dimension + i] * previous_velocities_val[n * this->spatial_dimension + i]; Real pred_vel = velocity_val[current_node * this->spatial_dimension + i] + 0.5 * time_step * acceleration_val[current_node * this->spatial_dimension + i]; dot_prod_pred_velocities += pred_vel * previous_velocities_val[n * this->spatial_dimension + i]; current_proj_vel_mag += velocity_val[current_node * this->spatial_dimension + i] * velocity_val[current_node * this->spatial_dimension + i]; } } current_proj_vel_mag = sqrt(current_proj_vel_mag); // if velocity has changed sign or has become very small we get into stick if ((dot_prod_velocities < 0.) || (dot_prod_pred_velocities < 0.) || (current_proj_vel_mag < tolerance)) { for (UInt i=0; i < this->spatial_dimension; ++i) { if(Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { //friction_forces_val[n*spatial_dimension + i] = residual_forces_val[n*spatial_dimension + i]; //residual_forces_val[n * this->spatial_dimension + i] =0.; residual_val [current_node * this->spatial_dimension + i] = 0.; velocity_val [current_node * this->spatial_dimension + i] = 0.; acceleration_val[current_node * this->spatial_dimension + i] = 0.; } //else //friction_forces_val[n*spatial_dimension + i] = 0.; //friction_forces_val[n*spatial_dimension + i] *= -1.; } node_is_sticking_val[n*2] = true; node_is_sticking_val[n*2+1] = true; } } // save current velocities for (UInt n=0; n < nb_active_impactor_nodes; ++n) { UInt current_node = active_impactor_nodes_val[n]; for(UInt i=0; i < spatial_dimension; ++i) { previous_velocities_val[n*spatial_dimension+i] = velocity_val[current_node*spatial_dimension+i]; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::addRegularizedFriction(const Real & regularizer) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(this->spatial_dimension == 2, "addRegularizedFriction is implemented only for 2D"); Real * residual_val = this->model.getResidual().values; Real * position_val = this->model.getCurrentPosition().values; for(UInt m=0; m < this->master_surfaces.size(); ++m) { Surface master = this->master_surfaces.at(m); // find the impactors information for this master surface ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; // find the friction coefficient object for this master ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master); AKANTU_DEBUG_ASSERT(it_fc != this->friction_coefficient.end(), "The master surface: " << master << "couldn't be found in friction_coefficient map"); FrictionCoefficient * fric_coef = it_fc->second; AKANTU_DEBUG_ASSERT(fric_coef != NULL, "There is no friction coefficient defined for master surface " << master); UInt nb_active_impactor_nodes = impactor_info->active_impactor_nodes->getSize(); // compute the friction coefficient for each active impactor node Vector<Real> friction_coefficient_values(nb_active_impactor_nodes, 1); Real * friction_coefficient_values_p = friction_coefficient_values.values; fric_coef->computeFrictionCoefficient(friction_coefficient_values); UInt * active_impactor_nodes_val = impactor_info->active_impactor_nodes->storage(); Real * direction_val = impactor_info->master_normals->storage(); bool * node_is_sticking_val = impactor_info->node_is_sticking->storage(); Real * friction_forces_val = impactor_info->friction_forces->storage(); Real * stick_positions_val = impactor_info->stick_positions->storage(); for (UInt n=0; n < nb_active_impactor_nodes; ++n) { UInt current_node = active_impactor_nodes_val[n]; Real normal_contact_force = 0.; Real friction_force = 0.; // find friction force mu * normal force for (UInt i=0; i<spatial_dimension; ++i) { if(!Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { normal_contact_force = std::abs(residual_val[current_node * this->spatial_dimension + i]); friction_force = friction_coefficient_values_p[n] * normal_contact_force; } } // compute F_(i+1)trial Real f_trial = Math::distance_2d(&(position_val[current_node * this->spatial_dimension]), &(stick_positions_val[n * this->spatial_dimension])); f_trial *= regularizer; Real delta_s_vector[this->spatial_dimension]; for (UInt i=0; i<spatial_dimension; ++i) { delta_s_vector[i] = position_val[current_node * this->spatial_dimension + i] - stick_positions_val[n * this->spatial_dimension + i]; delta_s_vector[i] *= -1.; } // if node is on its own stick position no need to compute friction force // this avoids nan on normalize2 if(Math::norm2(delta_s_vector) < Math::getTolerance()) { node_is_sticking_val[n*2] = true; node_is_sticking_val[n*2+1] = true; continue; } Math::normalize2(delta_s_vector); // check if node is still sticking if (f_trial <= friction_force) { friction_force = f_trial; // sticking position stays unchanged node_is_sticking_val[n*2] = true; node_is_sticking_val[n*2+1] = true; } else { node_is_sticking_val[n*2] = false; node_is_sticking_val[n*2+1] = false; Real delta_s = std::abs(f_trial - friction_force) / regularizer; // friction force stays unchanged for (UInt i=0; i<spatial_dimension; ++i) { stick_positions_val[n * this->spatial_dimension + i] -= delta_s * delta_s_vector[i]; } } // add friction force to residual for (UInt i=0; i < this->spatial_dimension; ++i) { Real directional_fric_force = friction_force * delta_s_vector[i]; friction_forces_val[n*this->spatial_dimension + i] = directional_fric_force; residual_val[current_node * this->spatial_dimension + i] += directional_fric_force; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::setStickPositionsToCurrentPositions(const Surface master) { AKANTU_DEBUG_IN(); Real * position_val = this->model.getCurrentPosition().values; // find the impactors information for this master surface ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; UInt nb_active_impactor_nodes = impactor_info->active_impactor_nodes->getSize(); UInt * active_impactor_nodes_val = impactor_info->active_impactor_nodes->storage(); Real * stick_positions_val = impactor_info->stick_positions->storage(); for (UInt n=0; n < nb_active_impactor_nodes; ++n) { UInt current_node = active_impactor_nodes_val[n]; // find friction force mu * normal force for (UInt i=0; i<spatial_dimension; ++i) { stick_positions_val[n*this->spatial_dimension + i] = position_val[current_node*this->spatial_dimension + i]; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::setFrictionCoefficient(FrictionCoefficient * fric_coefficient) { AKANTU_DEBUG_IN(); Surface master = fric_coefficient->getMasterSurface(); ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master); AKANTU_DEBUG_ASSERT(it_fc == this->friction_coefficient.end(), "There is already a friction coefficient for master surface: " << master); this->friction_coefficient[master] = fric_coefficient; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::removeFrictionCoefficient(const Surface master) { AKANTU_DEBUG_IN(); ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master); AKANTU_DEBUG_ASSERT(it_fc != this->friction_coefficient.end(), "There is no friction coefficient for master surface: " << master); this->friction_coefficient.erase(it_fc); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::getRestartInformation(std::map<std::string, VectorBase* > & map_to_fill, Surface master) { AKANTU_DEBUG_IN(); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; UInt nb_active_nodes = impactor_info->active_impactor_nodes->getSize(); // create vectors Vector<bool> * activity_of_nodes = new Vector<bool>(this->mesh.getNbNodes(), 1, false); Vector<ElementType> * element_type_of_nodes = new Vector<ElementType>(this->mesh.getNbNodes(), 1, _not_defined); Vector<Real> * normals_of_nodes = new Vector<Real>(this->mesh.getNbNodes(), this->spatial_dimension, 0.); Vector<bool> * sticking_of_nodes = new Vector<bool>(this->mesh.getNbNodes(), 2, false); Vector<Real> * friction_force_of_nodes = new Vector<Real>(this->mesh.getNbNodes(), this->spatial_dimension, 0.); Vector<Real> * stick_position_of_nodes = new Vector<Real>(this->mesh.getNbNodes(), this->spatial_dimension, 0.); Vector<Real> * residual_force_of_nodes = new Vector<Real>(this->mesh.getNbNodes(), this->spatial_dimension, 0.); Vector<Real> * previous_velocity_of_nodes = new Vector<Real>(this->mesh.getNbNodes(), this->spatial_dimension, 0.); Vector<Real> * friction_resistances_of_nodes = new Vector<Real>(this->mesh.getNbNodes(), 1, 0.); UInt * active_nodes = impactor_info->active_impactor_nodes->storage(); ElementType * element_type = &(*impactor_info->master_element_type)[0]; Real * master_normal = impactor_info->master_normals->storage(); bool * node_stick = impactor_info->node_is_sticking->storage(); Real * friction_force = impactor_info->friction_forces->storage(); Real * stick_position = impactor_info->stick_positions->storage(); Real * residual_force = impactor_info->residual_forces->storage(); Real * previous_velocity = impactor_info->previous_velocities->storage(); Real * friction_resistance = impactor_info->friction_resistances->storage(); for (UInt i=0; i<nb_active_nodes; ++i, ++active_nodes, ++element_type, ++friction_resistance) { (*activity_of_nodes)(*active_nodes) = true; (*element_type_of_nodes)(*active_nodes) = *element_type; (*friction_resistances_of_nodes)(*active_nodes) = *friction_resistance; for (UInt d=0; d<this->spatial_dimension; ++d, ++master_normal, ++friction_force, ++stick_position, ++residual_force, ++previous_velocity) { (*normals_of_nodes)(*active_nodes,d) = *master_normal; (*friction_force_of_nodes)(*active_nodes,d) = *friction_force; (*stick_position_of_nodes)(*active_nodes,d) = *stick_position; (*residual_force_of_nodes)(*active_nodes,d) = *residual_force; (*previous_velocity_of_nodes)(*active_nodes,d) = *previous_velocity; } for (UInt j=0; j<2; ++j, ++node_stick) { (*sticking_of_nodes)(*active_nodes,j) = *node_stick; } } map_to_fill["active_impactor_nodes"] = activity_of_nodes; map_to_fill["master_element_type"] = element_type_of_nodes; map_to_fill["master_normals"] = normals_of_nodes; map_to_fill["node_is_sticking"] = sticking_of_nodes; map_to_fill["friction_forces"] = friction_force_of_nodes; map_to_fill["stick_positions"] = stick_position_of_nodes; map_to_fill["residual_forces"] = residual_force_of_nodes; map_to_fill["previous_velocities"] = previous_velocity_of_nodes; map_to_fill["friction_resistances"] = friction_resistances_of_nodes; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::setRestartInformation(std::map<std::string, VectorBase* > & restart_map, Surface master) { AKANTU_DEBUG_IN(); ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; std::map < std::string, VectorBase* >::iterator it; it = restart_map.find("active_impactor_nodes"); Vector<bool> * ai_nodes = (Vector<bool> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry for active impactor nodes" << std::endl; } it = restart_map.find("master_element_type"); Vector<ElementType> * et_nodes = (Vector<ElementType> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry master element type" << std::endl; } it = restart_map.find("master_normals"); Vector<Real> * mn_nodes = (Vector<Real> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry for master normals" << std::endl; } it = restart_map.find("node_is_sticking"); Vector<bool> * is_nodes = (Vector<bool> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry node is sticking" << std::endl; } it = restart_map.find("friction_forces"); Vector<Real> * ff_nodes = (Vector<Real> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry friction forces" << std::endl; } it = restart_map.find("stick_positions"); Vector<Real> * sp_nodes = (Vector<Real> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry stick positions" << std::endl; } it = restart_map.find("residual_forces"); Vector<Real> * rf_nodes = (Vector<Real> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry residual forces" << std::endl; } it = restart_map.find("previous_velocities"); Vector<Real> * pv_nodes = (Vector<Real> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry previous velocities" << std::endl; } it = restart_map.find("friction_resistances"); Vector<Real> * fr_nodes = (Vector<Real> *)(it->second); if(it == restart_map.end()) { std::cout << "could not find map entry friction resistances" << std::endl; } UInt nb_nodes = this->mesh.getNbNodes(); for (UInt i=0; i<nb_nodes; ++i) { if ((*ai_nodes)(i)) { // get active_impactor_nodes and master_element_type information impactor_info->active_impactor_nodes->push_back(i); impactor_info->master_element_type->push_back((*et_nodes)(i)); // get master_normals and friction_forces information Real normal[this->spatial_dimension]; Real friction[this->spatial_dimension]; Real position[this->spatial_dimension]; Real residual[this->spatial_dimension]; Real velocity[this->spatial_dimension]; for (UInt d=0; d<this->spatial_dimension; ++d) { normal[d] = (*mn_nodes)(i,d); friction[d] = (*ff_nodes)(i,d); position[d] = (*sp_nodes)(i,d); residual[d] = (*rf_nodes)(i,d); velocity[d] = (*pv_nodes)(i,d); } impactor_info->master_normals->push_back(normal); impactor_info->friction_forces->push_back(friction); impactor_info->stick_positions->push_back(position); impactor_info->residual_forces->push_back(residual); impactor_info->previous_velocities->push_back(velocity); impactor_info->friction_resistances->push_back((*fr_nodes)(i)); // get node_is_sticking information bool stick[2]; for (UInt j=0; j<2; ++j) { stick[j] = (*is_nodes)(i,j); } impactor_info->node_is_sticking->push_back(stick); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactRigid::setSimplifiedPrakashCliftonFriction(Real v_star, Real length) { this->prakash = true; this->ref_velocity = v_star; this->characterstic_length = length; } /* -------------------------------------------------------------------------- */ void ContactRigid::unsetSimplifiedPrakashCliftonFriction() { this->prakash = false; } /* -------------------------------------------------------------------------- */ void ContactRigid::setPrakashCliftonToSteadyState(const Surface master) { AKANTU_DEBUG_IN(); Real * residual_val = this->model.getResidual().values; // find the impactors information for this master surface ContactRigid::SurfaceToImpactInfoMap::iterator it_imp; it_imp = this->impactors_information.find(master); AKANTU_DEBUG_ASSERT(it_imp != this->impactors_information.end(), "The master surface: " << master << "couldn't be found in impactors_information map"); ImpactorInformationPerMaster * impactor_info = it_imp->second; ContactRigid::SurfaceToFricCoefMap::iterator it_fc; it_fc = this->friction_coefficient.find(master); AKANTU_DEBUG_ASSERT(it_fc != this->friction_coefficient.end(), "The master surface: " << master << "couldn't be found in friction_coefficient map"); FrictionCoefficient * fric_coef = it_fc->second; AKANTU_DEBUG_ASSERT(fric_coef != NULL, "There is no friction coefficient defined for master surface " << master); UInt nb_active_impactor_nodes = impactor_info->active_impactor_nodes->getSize(); UInt * active_impactor_nodes_val = impactor_info->active_impactor_nodes->storage(); Real * direction_val = impactor_info->master_normals->storage(); Real * friction_resistances_val = impactor_info->friction_resistances->storage(); // compute the friction coefficient for each active impactor node Vector<Real> friction_coefficient_values(nb_active_impactor_nodes, 1); Real * friction_coefficient_values_p = friction_coefficient_values.values; fric_coef->computeFrictionCoefficient(friction_coefficient_values); for (UInt n=0; n < nb_active_impactor_nodes; ++n) { UInt current_node = active_impactor_nodes_val[n]; Real normal_contact_force = 0.; Real friction_force = 0.; for (UInt i=0; i < spatial_dimension; ++i) { if(!Math::are_float_equal(direction_val[n * this->spatial_dimension + i],0.)) { normal_contact_force = std::abs(residual_val[current_node * this->spatial_dimension + i]); friction_force = friction_coefficient_values_p[n] * normal_contact_force; } } friction_resistances_val[n] = friction_force; } AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 7fedfeb58..4e8ad3bf2 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,814 +1,819 @@ /** * @file material.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Tue Jul 27 11:43:41 2010 * * @brief Implementation of the common part of the material class * * @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 "material.hh" #include "solid_mechanics_model.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Memory(model.getMemoryID()), id(id), name(""), model(&model), stress("stress", id), strain("strain", id), element_filter("element_filter", id), // potential_energy_vector(false), potential_energy("potential_energy", id), is_non_local(false), interpolation_inverse_coordinates("interpolation inverse coordinates", id), interpolation_points_matrices("interpolation points matrices", id), is_init(false) { AKANTU_DEBUG_IN(); registerParam("rho", rho, 0., ParamAccessType(_pat_parsable | _pat_readable), "Density"); registerParam("id", this->id, _pat_readable); registerParam("name", name, ParamAccessType(_pat_parsable | _pat_readable)); spatial_dimension = this->model->getSpatialDimension(); /// allocate strain stress for local elements initInternalVector(strain, spatial_dimension * spatial_dimension); initInternalVector(stress, spatial_dimension * spatial_dimension); /// for each connectivity types allocate the element filer array of the material - initInternalVector(element_filter, 1); + initInternalVector(element_filter, 1, true); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::~Material() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool Material::parseParam(const std::string & key, const std::string & value, __attribute__ ((unused)) const ID & id) { try { params.parseParam(key, value); } catch(...) { return false; } return true; } /* -------------------------------------------------------------------------- */ void Material::initMaterial() { AKANTU_DEBUG_IN(); resizeInternalVector(stress); resizeInternalVector(strain); is_init = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<typename T> void Material::initInternalVector(ByElementTypeVector<T> & vect, UInt nb_component, + bool temporary, ElementKind element_kind) { AKANTU_DEBUG_IN(); model->getFEM().getMesh().initByElementTypeVector(vect, nb_component, spatial_dimension, false, element_kind); - registerInternal(vect); + if(!temporary) + registerInternal(vect); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<> void Material::registerInternal<Real>(ByElementTypeVector<Real> & vect) { internal_vectors_real[vect.getID()] = &vect; } template<> void Material::registerInternal<UInt>(ByElementTypeVector<UInt> & vect) { internal_vectors_uint[vect.getID()] = &vect; } /* -------------------------------------------------------------------------- */ template<typename T> void Material::resizeInternalVector(ByElementTypeVector<T> & by_el_type_vect, ElementKind element_kind) const { AKANTU_DEBUG_IN(); FEM * fem = & model->getFEM(); if (element_kind == _ek_cohesive) fem = & model->getFEM("CohesiveFEM"); const Mesh & mesh = fem->getMesh(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, element_kind); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, element_kind); for(; it != end; ++it) { const Vector<UInt> & elem_filter = element_filter(*it, gt); UInt nb_element = elem_filter.getSize(); UInt nb_quadrature_points = fem->getNbQuadraturePoints(*it, gt); UInt new_size = nb_element * nb_quadrature_points; Vector<T> & vect = by_el_type_vect(*it, gt); vect.resize(new_size); } } 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::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model->getSpatialDimension(); Vector<Real> & residual = const_cast<Vector<Real> &>(model->getResidual()); Mesh & mesh = model->getFEM().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { const Vector<Real> & shapes_derivatives = model->getFEM().getShapesDerivatives(*it, ghost_type); Vector<UInt> & elem_filter = element_filter(*it, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(*it, ghost_type); UInt nb_element = elem_filter.getSize(); /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by @f$\mathbf{B}^t \mathbf{\sigma}_q@f$ Vector<Real> * sigma_dphi_dx = new Vector<Real>(nb_element*nb_quadrature_points, size_of_shapes_derivatives, "sigma_x_dphi_/_dX"); Real * shapesd = shapes_derivatives.storage(); Real * shapesd_val; UInt * elem_filter_val = elem_filter.storage(); Vector<Real> * shapesd_filtered = new Vector<Real>(nb_element*nb_quadrature_points, size_of_shapes_derivatives, "filtered shapesd"); Real * shapesd_filtered_val = shapesd_filtered->values; for (UInt el = 0; el < nb_element; ++el) { shapesd_val = shapesd + elem_filter_val[el] * size_of_shapes_derivatives * nb_quadrature_points; memcpy(shapesd_filtered_val, shapesd_val, size_of_shapes_derivatives * nb_quadrature_points * sizeof(Real)); shapesd_filtered_val += size_of_shapes_derivatives * nb_quadrature_points; } Vector<Real> & stress_vect = stress(*it, ghost_type); // Vector<Real>::iterator<types::Matrix> sigma = stress_vect.begin(spatial_dimension, spatial_dimension); // Vector<Real>::iterator<types::Matrix> sigma_end = stress_vect.end(spatial_dimension, spatial_dimension); // Vector<Real>::iterator<types::Matrix> nabla_B = shapesd_filtered->begin(nb_nodes_per_element, spatial_dimension); // Vector<Real>::iterator<types::Matrix> sigma_dphi_dx_it = sigma_dphi_dx->begin(nb_nodes_per_element, spatial_dimension); // for (; sigma != sigma_end; ++sigma, ++nabla_B, ++sigma_dphi_dx_it) { // sigma_dphi_dx_it->mul<true,false>(*nabla_B, *sigma); // } Math::matrix_matrixt(nb_nodes_per_element, spatial_dimension, spatial_dimension, *shapesd_filtered, stress_vect, *sigma_dphi_dx); 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$ */ Vector<Real> * int_sigma_dphi_dx = new Vector<Real>(nb_element, nb_nodes_per_element * spatial_dimension, "int_sigma_x_dphi_/_dX"); model->getFEM().integrate(*sigma_dphi_dx, *int_sigma_dphi_dx, size_of_shapes_derivatives, *it, ghost_type, &elem_filter); delete sigma_dphi_dx; /// assemble model->getFEM().assembleVector(*int_sigma_dphi_dx, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, &elem_filter, -1); delete int_sigma_dphi_dx; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stress from the strain * * @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(); resizeInternalVector(stress); resizeInternalVector(strain); UInt spatial_dimension = model->getSpatialDimension(); Mesh::type_iterator it = model->getFEM().getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = model->getFEM().getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Vector<UInt> & elem_filter = element_filter(*it, ghost_type); Vector<Real> & strain_vect = strain(*it, ghost_type); /// compute @f$\nabla u@f$ model->getFEM().gradientOnQuadraturePoints(model->getDisplacement(), strain_vect, spatial_dimension, *it, ghost_type, &elem_filter); /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$ computeStress(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::setToSteadyState(GhostType ghost_type) { AKANTU_DEBUG_IN(); const Vector<Real> & displacement = model->getDisplacement(); resizeInternalVector(strain); UInt spatial_dimension = model->getSpatialDimension(); Mesh::type_iterator it = model->getFEM().getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = model->getFEM().getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Vector<UInt> & elem_filter = element_filter(*it, ghost_type); Vector<Real> & strain_vect = strain(*it, ghost_type); /// compute @f$\nabla u@f$ model->getFEM().gradientOnQuadraturePoints(displacement, strain_vect, spatial_dimension, *it, ghost_type, &elem_filter); setToSteadyState(*it, 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(); Mesh & mesh = model->getFEM().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { switch(spatial_dimension) { case 1: { assembleStiffnessMatrix<1>(*it, ghost_type); break; } case 2: { assembleStiffnessMatrix<2>(*it, ghost_type); break; } case 3: { assembleStiffnessMatrix<3>(*it, ghost_type); break; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void Material::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast<SparseMatrix &>(model->getStiffnessMatrix()); const Vector<Real> & shapes_derivatives = model->getFEM().getShapesDerivatives(type,ghost_type); Vector<UInt> & elem_filter = element_filter(type, ghost_type); Vector<Real> & strain_vect = strain(type, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(type, ghost_type); strain_vect.resize(nb_quadrature_points * nb_element); model->getFEM().gradientOnQuadraturePoints(model->getDisplacement(), strain_vect, dim, type, ghost_type, &elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Vector<Real> * tangent_stiffness_matrix = new Vector<Real>(nb_element*nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); Vector<Real> * shapes_derivatives_filtered = new Vector<Real>(nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); Vector<Real>::const_iterator<types::Matrix> shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Vector<Real>::iterator<types::Matrix> 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; Vector<Real> * bt_d_b = new Vector<Real>(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); types::Matrix B(tangent_size, dim * nb_nodes_per_element); types::Matrix Bt_D(dim * nb_nodes_per_element, tangent_size); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(nb_nodes_per_element, spatial_dimension); Vector<Real>::iterator<types::Matrix> Bt_D_B_it = bt_d_b->begin(dim*nb_nodes_per_element, dim*nb_nodes_per_element); Vector<Real>::iterator<types::Matrix> D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); Vector<Real>::iterator<types::Matrix> 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) { types::Matrix & D = *D_it; types::Matrix & Bt_D_B = *Bt_D_B_it; transferBMatrixToSymVoigtBMatrix<dim>(*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 shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Vector<Real> * K_e = new Vector<Real>(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); model->getFEM().integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, &elem_filter); delete bt_d_b; model->getFEM().assembleMatrix(*K_e, K, spatial_dimension, type, ghost_type, &elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if(ghost_type != _not_ghost) return; Real * epot = potential_energy(el_type, ghost_type).storage(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computePotentialEnergyOnQuad(grad_u, sigma, *epot); epot++; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergyByElement() { AKANTU_DEBUG_IN(); Mesh & mesh = model->getFEM().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension); for(; it != last_type; ++it) { if(!potential_energy.exists(*it, _not_ghost)) { UInt nb_element = element_filter(*it, _not_ghost).getSize(); UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(*it, _not_ghost); potential_energy.alloc(nb_element * nb_quadrature_points, 1, *it, _not_ghost); } computePotentialEnergy(*it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real epot = 0.; computePotentialEnergyByElement(); /// integrate the potential energy for each type of elements Mesh & mesh = model->getFEM().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension); for(; it != last_type; ++it) { epot += model->getFEM().integrate(potential_energy(*it, _not_ghost), *it, _not_ghost, &element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(std::string type) { AKANTU_DEBUG_IN(); if(type == "potential") return getPotentialEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ void Material::computeQuadraturePointsCoordinates(ByElementTypeReal & quadrature_points_coordinates, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); const Mesh & mesh = model->getFEM().getMesh(); Vector<Real> nodes_coordinates(mesh.getNodes(), true); nodes_coordinates += model->getDisplacement(); 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) { const Vector<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_tot_quad = model->getFEM().getNbQuadraturePoints(*it, ghost_type) * nb_element; Vector<Real> & quads = quadrature_points_coordinates(*it, ghost_type); quads.resize(nb_tot_quad); model->getFEM().interpolateOnQuadraturePoints(nodes_coordinates, quads, spatial_dimension, *it, ghost_type, &elem_filter); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::initElementalFieldInterpolation(ByElementTypeReal & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); const Mesh & mesh = model->getFEM().getMesh(); ByElementTypeReal quadrature_points_coordinates("quadrature_points_coordinates_tmp_nl", id); mesh.initByElementTypeVector(quadrature_points_coordinates, spatial_dimension, 0); computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); for (; it != last; ++it) { UInt nb_element = mesh.getNbElement(*it); if (nb_element == 0) continue; ElementType type = *it; #define AKANTU_INIT_INTERPOLATE_ELEMENTAL_FIELD(type) \ initElementalFieldInterpolation<type>(quadrature_points_coordinates(type), \ interpolation_points_coordinates(type)) AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(AKANTU_INIT_INTERPOLATE_ELEMENTAL_FIELD); #undef AKANTU_INIT_INTERPOLATE_ELEMENTAL_FIELD } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void Material::initElementalFieldInterpolation(const Vector<Real> & quad_coordinates, const Vector<Real> & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); UInt size_inverse_coords = getSizeElementalFieldInterpolationCoodinates<type>(); Vector<UInt> & elem_fil = element_filter(type); UInt nb_element = elem_fil.getSize(); UInt nb_quad_per_element = model->getFEM().getNbQuadraturePoints(type); UInt nb_interpolation_points = interpolation_points_coordinates.getSize(); AKANTU_DEBUG_ASSERT(nb_interpolation_points % nb_element == 0, "Can't interpolate elemental field on elements, the coordinates vector has a wrong size"); UInt nb_interpolation_points_per_elem = nb_interpolation_points / nb_element; if(!interpolation_inverse_coordinates.exists(type)) interpolation_inverse_coordinates.alloc(nb_element, size_inverse_coords*size_inverse_coords, type); if(!interpolation_points_matrices.exists(type)) interpolation_points_matrices.alloc(nb_element, nb_interpolation_points_per_elem * size_inverse_coords, type); Vector<Real> & interp_inv_coord = interpolation_inverse_coordinates(type); Vector<Real> & interp_points_mat = interpolation_points_matrices(type); types::Matrix quad_coord_matrix(size_inverse_coords, size_inverse_coords); Vector<Real>::const_iterator<types::Matrix> quad_coords_it = quad_coordinates.begin_reinterpret(nb_quad_per_element, spatial_dimension, nb_element, nb_quad_per_element * spatial_dimension); Vector<Real>::const_iterator<types::Matrix> points_coords_it = interpolation_points_coordinates.begin_reinterpret(nb_interpolation_points_per_elem, spatial_dimension, nb_element, nb_interpolation_points_per_elem * spatial_dimension); Vector<Real>::iterator<types::Matrix> inv_quad_coord_it = interp_inv_coord.begin(size_inverse_coords, size_inverse_coords); Vector<Real>::iterator<types::Matrix> inv_points_mat_it = interp_points_mat.begin(nb_interpolation_points_per_elem, size_inverse_coords); /// loop over the elements of the current material and element type for (UInt el = 0; el < nb_element; ++el) { /// matrix containing the quadrature points coordinates const types::Matrix & quad_coords = *quad_coords_it; /// matrix to store the matrix inversion result types::Matrix & inv_quad_coord_matrix = *inv_quad_coord_it; /// insert the quad coordinates in a matrix compatible with the interpolation buildElementalFieldInterpolationCoodinates<type>(quad_coords, quad_coord_matrix); /// invert the interpolation matrix inv_quad_coord_matrix.inverse(quad_coord_matrix); /// matrix containing the interpolation points coordinates const types::Matrix & points_coords = *points_coords_it; /// matrix to store the interpolation points coordinates /// compatible with these functions types::Matrix & inv_points_coord_matrix = *inv_points_mat_it; /// insert the quad coordinates in a matrix compatible with the interpolation buildElementalFieldInterpolationCoodinates<type>(points_coords, inv_points_coord_matrix); ++inv_quad_coord_it; ++inv_points_mat_it; ++quad_coords_it; ++points_coords_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(const ElementType type, Vector<Real> & result) { AKANTU_DEBUG_IN(); #define INTERPOLATE_ELEMENTAL_FIELD(type) \ interpolateElementalField<type>(stress(type), \ result) \ AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INTERPOLATE_ELEMENTAL_FIELD); #undef INTERPOLATE_ELEMENTAL_FIELD AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void Material::interpolateElementalField(const Vector<Real> & field, Vector<Real> & result) { AKANTU_DEBUG_IN(); Vector<UInt> & elem_fil = element_filter(type); UInt nb_element = elem_fil.getSize(); UInt nb_quad_per_element = model->getFEM().getNbQuadraturePoints(type); UInt size_inverse_coords = getSizeElementalFieldInterpolationCoodinates<type>(); types::Matrix coefficients(nb_quad_per_element, field.getNbComponent()); const Vector<Real> & interp_inv_coord = interpolation_inverse_coordinates(type); const Vector<Real> & interp_points_coord = interpolation_points_matrices(type); UInt nb_interpolation_points_per_elem = interp_points_coord.getNbComponent() / size_inverse_coords; Vector<Real> filtered_field(nb_element, nb_quad_per_element); extractElementalFieldForInterplation<type>(field, filtered_field); Vector<Real>::const_iterator<types::Matrix> field_it = field.begin_reinterpret(nb_quad_per_element, field.getNbComponent(), nb_element, nb_quad_per_element * field.getNbComponent()); Vector<Real>::const_iterator<types::Matrix> interpolation_points_coordinates_it = interp_points_coord.begin(nb_interpolation_points_per_elem, size_inverse_coords); Vector<Real>::iterator<types::Matrix> result_it = result.begin_reinterpret(nb_interpolation_points_per_elem, field.getNbComponent(), nb_element, nb_interpolation_points_per_elem * field.getNbComponent()); Vector<Real>::const_iterator<types::Matrix> inv_quad_coord_it = interp_inv_coord.begin(size_inverse_coords, size_inverse_coords); /// loop over the elements of the current material and element type for (UInt el = 0; el < nb_element; ++el, ++field_it, ++result_it, ++inv_quad_coord_it, ++interpolation_points_coordinates_it) { /** * matrix containing the inversion of the quadrature points' * coordinates */ const types::Matrix & inv_quad_coord_matrix = *inv_quad_coord_it; /** * multiply it by the field values over quadrature points to get * the interpolation coefficients */ coefficients.mul<false, false>(inv_quad_coord_matrix, *field_it); /// matrix containing the points' coordinates const types::Matrix & coord = *interpolation_points_coordinates_it; /// multiply the coordinates matrix by the coefficients matrix and store the result (*result_it).mul<false, false>(coord, coefficients); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ const Vector<Real> & Material::getVector(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 << id << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getVector<Real>(fvect_id); } catch(debug::Exception & e) { AKANTU_EXCEPTION("The material " << name << "(" <<id << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ Vector<Real> & Material::getVector(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 << id << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getVector<Real>(fvect_id); } catch(debug::Exception & e) { AKANTU_EXCEPTION("The material " << name << "(" <<id << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ - 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 = id.substr(id.find_last_of(":") + 1); stream << space << "Material " << type << " [" << std::endl; params.printself(stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ template void Material::initInternalVector<Real>(ByElementTypeVector<Real> & vect, UInt nb_component, + bool temporary, ElementKind element_kind); template void Material::initInternalVector<UInt>(ByElementTypeVector<UInt> & vect, UInt nb_component, + bool temporary, ElementKind element_kind); template void Material::initInternalVector<Int>(ByElementTypeVector<Int> & vect, UInt nb_component, + bool temporary, ElementKind element_kind); template void Material::initInternalVector<bool>(ByElementTypeVector<bool> & vect, UInt nb_component, + bool temporary, ElementKind element_kind); template void Material::resizeInternalVector<Real>(ByElementTypeVector<Real> & vect, ElementKind element_kind) const; template void Material::resizeInternalVector<UInt>(ByElementTypeVector<UInt> & vect, ElementKind element_kind) const; template void Material::resizeInternalVector<Int>(ByElementTypeVector<Int> & vect, ElementKind element_kind) const; template void Material::resizeInternalVector<bool>(ByElementTypeVector<bool> & vect, ElementKind element_kind) const; __END_AKANTU__ diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh index bb18ebf86..9825aaaf4 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,545 +1,553 @@ /** * @file material.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Fri Jul 23 09:06:29 2010 * * @brief Mother class for all materials * * @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 "parser.hh" #include "data_accessor.hh" #include "material_parameters.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_HH__ #define __AKANTU_MATERIAL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Model; class SolidMechanicsModel; class CommunicationBuffer; } __BEGIN_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, * Vector<Real> & tangent_matrix, * GhostType ghost_type = _not_ghost); * \endcode * */ class Material : protected Memory, public DataAccessor, public Parsable, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Material(SolidMechanicsModel & model, const ID & id = ""); virtual ~Material(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// register a material parameter template<class T> void registerParam(std::string name, T & variable, T default_value, ParamAccessType type, std::string description = ""); template<class T> void registerParam(std::string name, T & variable, ParamAccessType type, std::string description = ""); template<typename T> void registerInternal(__attribute__((unused)) ByElementTypeVector<T> & vect) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// read parameter from file virtual bool parseParam(const std::string & key, const std::string & value, const ID & id); /// function called to update the internal parameters when the modifiable /// parameters are modified virtual void updateInternalParameters() {} /// initialize the material computed parameter virtual void initMaterial(); /// compute the residual for this material virtual void updateResidual(GhostType ghost_type = _not_ghost); void assembleResidual(GhostType ghost_type); /// compute the residual for this material virtual void computeAllStresses(GhostType ghost_type = _not_ghost); virtual void computeAllNonLocalStresses(__attribute__((unused)) 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); /// compute the stable time step for an element of size h virtual Real getStableTimeStep(__attribute__((unused)) Real h, __attribute__((unused)) const Element & element = ElementNull) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the p-wave speed in the material virtual Real getPushWaveSpeed() const { AKANTU_DEBUG_TO_IMPLEMENT(); }; /// compute the s-wave speed in the material virtual Real getShearWaveSpeed() const { AKANTU_DEBUG_TO_IMPLEMENT(); }; /// add an element to the local mesh filter inline UInt addElement(const ElementType & type, UInt element, const GhostType & ghost_type); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points */ virtual void interpolateStress(const ElementType type, Vector<Real> & result); /** * function to initialize the elemental field interpolation * function by inverting the quadrature points' coordinates */ virtual void initElementalFieldInterpolation(ByElementTypeReal & interpolation_points_coordinates); protected: /// constitutive law virtual void computeStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// 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) {} /// compute the tangent stiffness matrix virtual void computeTangentModuli(__attribute__((unused)) const ElementType & el_type, __attribute__((unused)) Vector<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); template<UInt dim> void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// transfer the B matrix to a Voigt notation B matrix template<UInt dim> inline void transferBMatrixToSymVoigtBMatrix(const types::Matrix & B, types::Matrix & Bvoigt, UInt nb_nodes_per_element) const; inline UInt getTangentStiffnessVoigtSize(UInt spatial_dimension) const; /// compute the potential energy by element void computePotentialEnergyByElement(); /// compute the coordinates of the quadrature points void computeQuadraturePointsCoordinates(ByElementTypeReal & quadrature_points_coordinates, const GhostType & ghost_type) const; /// interpolate an elemental field on given points for each element template <ElementType type> void interpolateElementalField(const Vector<Real> & field, Vector<Real> & result); /// template function to initialize the elemental field interpolation template <ElementType type> void initElementalFieldInterpolation(const Vector<Real> & quad_coordinates, const Vector<Real> & interpolation_points_coordinates); /// build the coordinate matrix for the interpolation on elemental field template <ElementType type> inline void buildElementalFieldInterpolationCoodinates(const types::Matrix & coordinates, types::Matrix & coordMatrix); /// get the size of the coordiante matrix used in the interpolation template <ElementType type> inline UInt getSizeElementalFieldInterpolationCoodinates(); /// extract the field values corresponding to the quadrature points used for the interpolation template <ElementType type> inline void extractElementalFieldForInterplation(const Vector<Real> & field, Vector<Real> & filtered_field); /* ------------------------------------------------------------------------ */ /* Function for all materials */ /* ------------------------------------------------------------------------ */ protected: /// compute the potential energy for on element inline void computePotentialEnergyOnQuad(types::Matrix & grad_u, types::Matrix & sigma, Real & epot); protected: /// allocate an internal vector template<typename T> void initInternalVector(ByElementTypeVector<T> & vect, UInt nb_component, + bool temporary = false, ElementKind element_kind = _ek_regular); public: /// resize an internal vector template<typename T> void resizeInternalVector(ByElementTypeVector<T> & vect, ElementKind element_kind = _ek_regular) const; /* ------------------------------------------------------------------------ */ template<UInt dim> inline void gradUToF(const types::Matrix & grad_u, types::Matrix & F); inline void rightCauchy(const types::Matrix & F, types::Matrix & C); inline void leftCauchy (const types::Matrix & F, types::Matrix & B); /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: - virtual inline UInt getNbDataToPack (const Element & element, SynchronizationTag tag) const; - virtual inline UInt getNbDataToUnpack(const Element & element, SynchronizationTag tag) const; - - virtual UInt getNbDataToPack(__attribute__((unused)) SynchronizationTag tag) const { - return 0; - } - - virtual UInt getNbDataToUnpack(__attribute__((unused)) SynchronizationTag tag) const { - return 0; - } + virtual inline UInt getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const; + virtual inline void packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const; - virtual inline void packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const; + virtual inline void unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag); - virtual void packData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const UInt index, - __attribute__((unused)) SynchronizationTag tag) const { - } + template<typename T> + inline void packElementDataHelper(const ByElementTypeVector<T> & data_to_pack, + CommunicationBuffer & buffer, + const Vector<Element> & elements) const; - virtual inline void unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag); + template<typename T> + inline void unpackElementDataHelper(ByElementTypeVector<T> & data_to_unpack, + CommunicationBuffer & buffer, + const Vector<Element> & elements) const; - virtual void unpackData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const UInt index, - __attribute__((unused)) SynchronizationTag tag) { - } +protected: + template<typename T, bool pack_helper> + inline void packUnpackElementDataHelper(ByElementTypeVector<T> & data_to_pack, + CommunicationBuffer & buffer, + const Vector<Element> & elements) const; +public: + inline UInt getNbQuadraturePoints(const Vector<Element> & elements) const; +public: /* ------------------------------------------------------------------------ */ virtual inline void onElementsAdded(const Vector<Element> & element_list); + virtual inline void onElementsRemoved(const Vector<Element> & element_list, + const ByElementTypeUInt & new_numbering); + +protected: + template<typename T> + void removeQuadraturePointsFromVectors(ByElementTypeVector<T> & data, + const ByElementTypeUInt & new_numbering); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Model, *model, const SolidMechanicsModel &) AKANTU_GET_MACRO(ID, id, const ID &); AKANTU_GET_MACRO(Rho, rho, Real); AKANTU_SET_MACRO(Rho, rho, Real); Real getPotentialEnergy(); virtual Real getEnergy(std::string type); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementFilter, element_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Strain, strain, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PotentialEnergy, potential_energy, Real); bool isNonLocal() const { return is_non_local; } const Vector<Real> & getVector(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; Vector<Real> & getVector(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost); template<typename T> inline T getParam(const ID & param) const; template<typename T> inline void setParam(const ID & param, T value); protected: bool isInit() const { return is_init; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the material ID id; /// material name std::string name; /// The model to witch the material belong SolidMechanicsModel * model; /// density : rho Real rho; /// stresses arrays ordered by element types ByElementTypeReal stress; /// strains arrays ordered by element types ByElementTypeReal strain; /// list of element handled by the material ByElementTypeUInt element_filter; /// is the vector for potential energy initialized // bool potential_energy_vector; /// potential energy by element ByElementTypeReal potential_energy; /// tell if using in non local mode or not bool is_non_local; /// spatial dimension UInt spatial_dimension; /// elemental field interpolation coordinates ByElementTypeReal interpolation_inverse_coordinates; /// elemental field interpolation points ByElementTypeReal interpolation_points_matrices; /// list of the paramters MaterialParameters params; private: /// boolean to know if the material has been initialized bool is_init; std::map<ID, ByElementTypeReal *> internal_vectors_real; std::map<ID, ByElementTypeUInt *> internal_vectors_uint; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "material_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Material & _this) { _this.printself(stream); return stream; } __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* Auto loop */ /* -------------------------------------------------------------------------- */ #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type) \ Vector<Real>::iterator<types::Matrix> strain_it = \ this->strain(el_type, ghost_type).begin(spatial_dimension, \ spatial_dimension); \ Vector<Real>::iterator<types::Matrix> strain_end = \ this->strain(el_type, ghost_type).end(spatial_dimension, \ spatial_dimension); \ Vector<Real>::iterator<types::Matrix> stress_it = \ this->stress(el_type, ghost_type).begin(spatial_dimension, \ spatial_dimension); \ \ for(;strain_it != strain_end; ++strain_it, ++stress_it) { \ types::Matrix & __attribute__((unused)) grad_u = *strain_it; \ types::Matrix & __attribute__((unused)) sigma = *stress_it #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END \ } \ #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_mat) \ Vector<Real>::iterator<types::Matrix> strain_it = \ this->strain(el_type, ghost_type).begin(spatial_dimension, \ spatial_dimension); \ Vector<Real>::iterator<types::Matrix> strain_end = \ this->strain(el_type, ghost_type).end(spatial_dimension, \ spatial_dimension); \ \ UInt tangent_size = \ this->getTangentStiffnessVoigtSize(spatial_dimension); \ Vector<Real>::iterator<types::Matrix> tangent_it = \ tangent_mat.begin(tangent_size, \ tangent_size); \ \ for(;strain_it != strain_end; ++strain_it, ++tangent_it) { \ types::Matrix & __attribute__((unused)) grad_u = *strain_it; \ types::Matrix & tangent = *tangent_it #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END \ } /* -------------------------------------------------------------------------- */ /* Material list */ /* -------------------------------------------------------------------------- */ #define AKANTU_CORE_MATERIAL_LIST \ ((2, (elastic , MaterialElastic ))) \ ((2, (elastic_orthotropic, MaterialElasticOrthotropic ))) \ ((2, (neohookean , MaterialNeohookean ))) \ ((2, (sls_deviatoric , MaterialStandardLinearSolidDeviatoric))) \ ((2, (ve_stiffness_prop , MaterialStiffnessProportional ))) #define AKANTU_COHESIVE_MATERIAL_LIST \ ((2, (cohesive_bilinear , MaterialCohesiveBilinear ))) \ ((2, (cohesive_linear , MaterialCohesiveLinear ))) \ ((2, (cohesive_linear_extrinsic, MaterialCohesiveLinearExtrinsic ))) \ ((2, (cohesive_linear_exponential_extrinsic, MaterialCohesiveLinearExponentialExtrinsic ))) \ ((2, (cohesive_exponential , MaterialCohesiveExponential ))) #define AKANTU_DAMAGE_MATERIAL_LIST \ ((2, (damage_linear , MaterialDamageLinear ))) \ ((2, (marigo , MaterialMarigo ))) \ ((2, (mazars , MaterialMazars ))) \ ((2, (vreepeerlings , MaterialVreePeerlings ))) #ifdef AKANTU_DAMAGE_NON_LOCAL #define AKANTU_MATERIAL_WEIGHT_FUNCTION_TMPL_LIST \ ((stress_wf, StressBasedWeightFunction )) \ ((damage_wf, DamagedWeightFunction )) \ ((remove_wf, RemoveDamagedWeightFunction)) \ ((base_wf, BaseWeightFunction )) #define AKANTU_MATERIAL_VREEPEERLINGS_WEIGHT_FUNCTION_TMPL_LIST \ AKANTU_MATERIAL_WEIGHT_FUNCTION_TMPL_LIST \ ((removed_damrate_wf, RemoveDamagedWithDamageRateWeightFunction)) #define AKANTU_DAMAGE_NON_LOCAL_MATERIAL_LIST \ ((3, (marigo_non_local , MaterialMarigoNonLocal, \ AKANTU_MATERIAL_WEIGHT_FUNCTION_TMPL_LIST))) \ ((2, (mazars_non_local , MaterialMazarsNonLocal ))) \ ((3, (vreepeerlings_non_local, MaterialVreePeerlingsNonLocal, \ AKANTU_MATERIAL_VREEPEERLINGS_WEIGHT_FUNCTION_TMPL_LIST))) #else # define AKANTU_DAMAGE_NON_LOCAL_MATERIAL_LIST #endif #define AKANTU_MATERIAL_LIST \ AKANTU_CORE_MATERIAL_LIST \ AKANTU_COHESIVE_MATERIAL_LIST \ AKANTU_DAMAGE_MATERIAL_LIST \ AKANTU_DAMAGE_NON_LOCAL_MATERIAL_LIST #define INSTANSIATE_MATERIAL(mat_name) \ template class mat_name<1>; \ template class mat_name<2>; \ template class mat_name<3> #if defined(__INTEL_COMPILER) #pragma warning ( push ) /* warning #654: overloaded virtual function "akantu::Material::computeStress" is only partially overridden in class "akantu::Material*" */ #pragma warning ( disable : 654 ) #endif //defined(__INTEL_COMPILER) /* -------------------------------------------------------------------------- */ // elastic materials #include "material_elastic.hh" #include "material_neohookean.hh" #include "material_elastic_orthotropic.hh" // visco-elastic materials #include "material_stiffness_proportional.hh" #include "material_standard_linear_solid_deviatoric.hh" // damage materials #include "material_damage.hh" #include "material_marigo.hh" #include "material_mazars.hh" #include "material_damage_linear.hh" #include "material_vreepeerlings.hh" #if defined(AKANTU_DAMAGE_NON_LOCAL) # include "material_marigo_non_local.hh" # include "material_mazars_non_local.hh" # include "material_vreepeerlings_non_local.hh" #endif // cohesive materials #include "material_cohesive.hh" #include "material_cohesive_linear.hh" #include "material_cohesive_bilinear.hh" #include "material_cohesive_linear_extrinsic.hh" #include "material_cohesive_exponential.hh" #include "material_cohesive_linear_exponential_extrinsic.hh" #if defined(__INTEL_COMPILER) #pragma warning ( pop ) #endif //defined(__INTEL_COMPILER) #endif /* __AKANTU_MATERIAL_HH__ */ diff --git a/src/model/solid_mechanics/material_inline_impl.cc b/src/model/solid_mechanics/material_inline_impl.cc index d93822dad..c8f5696ad 100644 --- a/src/model/solid_mechanics/material_inline_impl.cc +++ b/src/model/solid_mechanics/material_inline_impl.cc @@ -1,268 +1,427 @@ /** * @file material_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Tue Jul 27 11:57:43 2010 * * @brief Implementation of the inline functions of the class material * * @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/>. * */ __END_AKANTU__ #include "solid_mechanics_model.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const ElementType & type, UInt element, const GhostType & ghost_type) { element_filter(type, ghost_type).push_back(element); return element_filter(type, ghost_type).getSize()-1; } /* -------------------------------------------------------------------------- */ inline UInt Material::getTangentStiffnessVoigtSize(UInt dim) const { return (dim * (dim - 1) / 2 + dim); } /* -------------------------------------------------------------------------- */ template<UInt dim> inline void Material::gradUToF(const types::Matrix & grad_u, types::Matrix & F) { UInt size_F = F.size(); AKANTU_DEBUG_ASSERT(F.size() >= grad_u.size() && grad_u.size() == dim, "The dimension of the tensor F should be greater or equal to the dimension of the tensor grad_u."); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) F(i, j) = grad_u(i, j); for (UInt i = 0; i < size_F; ++i) F(i, i) += 1; } /* -------------------------------------------------------------------------- */ inline void Material::rightCauchy(const types::Matrix & F, types::Matrix & C) { C.mul<true, false>(F, F); } /* -------------------------------------------------------------------------- */ inline void Material::leftCauchy(const types::Matrix & F, types::Matrix & B) { B.mul<false, true>(F, F); } /* -------------------------------------------------------------------------- */ inline void Material::computePotentialEnergyOnQuad(types::Matrix & grad_u, types::Matrix & sigma, Real & epot) { epot = 0.; for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) epot += sigma(i, j) * grad_u(i, j); epot *= .5; } /* -------------------------------------------------------------------------- */ template<UInt dim> inline void Material::transferBMatrixToSymVoigtBMatrix(const types::Matrix & B, types::Matrix & Bvoigt, UInt nb_nodes_per_element) const { Bvoigt.clear(); for (UInt i = 0; i < dim; ++i) for (UInt n = 0; n < nb_nodes_per_element; ++n) Bvoigt(i, i + n*dim) = B(n, i); if(dim == 2) { ///in 2D, fill the @f$ [\frac{\partial N_i}{\partial x}, \frac{\partial N_i}{\partial y}]@f$ row for (UInt n = 0; n < nb_nodes_per_element; ++n) { Bvoigt(2, 1 + n*2) = B(n, 0); Bvoigt(2, 0 + n*2) = B(n, 1); } } if(dim == 3) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { Real dndx = B(n, 0); Real dndy = B(n, 1); Real dndz = B(n, 2); ///in 3D, fill the @f$ [0, \frac{\partial N_i}{\partial y}, \frac{N_i}{\partial z}]@f$ row Bvoigt(3, 1 + n*3) = dndz; Bvoigt(3, 2 + n*3) = dndy; ///in 3D, fill the @f$ [\frac{\partial N_i}{\partial x}, 0, \frac{N_i}{\partial z}]@f$ row Bvoigt(4, 0 + n*3) = dndz; Bvoigt(4, 2 + n*3) = dndx; ///in 3D, fill the @f$ [\frac{\partial N_i}{\partial x}, \frac{N_i}{\partial y}, 0]@f$ row Bvoigt(5, 0 + n*3) = dndy; Bvoigt(5, 1 + n*3) = dndx; } } } /* -------------------------------------------------------------------------- */ template<ElementType type> inline void Material::buildElementalFieldInterpolationCoodinates(__attribute__((unused)) const types::Matrix & coordinates, __attribute__((unused)) types::Matrix & coordMatrix) { AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_triangle_3>(const types::Matrix & coordinates, types::Matrix & coordMatrix) { for (UInt i = 0; i < coordinates.rows(); ++i) coordMatrix(i, 0) = 1; } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_triangle_6>(const types::Matrix & coordinates, types::Matrix & coordMatrix) { UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(_triangle_6); for (UInt i = 0; i < coordinates.rows(); ++i) { coordMatrix(i, 0) = 1; for (UInt j = 1; j < nb_quadrature_points; ++j) coordMatrix(i, j) = coordinates(i, j-1); } } /* -------------------------------------------------------------------------- */ template<ElementType type> inline UInt Material::getSizeElementalFieldInterpolationCoodinates() { return model->getFEM().getNbQuadraturePoints(type); } /* -------------------------------------------------------------------------- */ template <ElementType type> inline void Material::extractElementalFieldForInterplation(const Vector<Real> & field, Vector<Real> & filtered_field) { filtered_field.copy(field); } /* -------------------------------------------------------------------------- */ template<typename T> void Material::registerParam(std::string name, T & variable, T default_value, ParamAccessType type, std::string description) { AKANTU_DEBUG_IN(); params.registerParam<T>(name, variable, default_value, type, description); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<typename T> void Material::registerParam(std::string name, T & variable, ParamAccessType type, std::string description) { AKANTU_DEBUG_IN(); params.registerParam<T>(name, variable, type, description); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -inline UInt Material::getNbDataToPack(const Element & element, - SynchronizationTag tag) const { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); - if(tag == _gst_smm_stress) return spatial_dimension * spatial_dimension * sizeof(Real) * nb_quadrature_points; +inline UInt Material::getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const { + //UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); + //UInt size = 0; + if(tag == _gst_smm_stress) { + return spatial_dimension * spatial_dimension * sizeof(Real) * this->getNbQuadraturePoints(elements); + } return 0; } /* -------------------------------------------------------------------------- */ -inline UInt Material::getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); - if(tag == _gst_smm_stress) return spatial_dimension * spatial_dimension * sizeof(Real) * nb_quadrature_points; - return 0; +inline void Material::packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const { + if(tag == _gst_smm_stress) { + packElementDataHelper(stress, buffer, elements); + // UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); + // Vector<Real>::const_iterator<types::Matrix> stress_it = stress(element.type, _not_ghost).begin(spatial_dimension, spatial_dimension); + // stress_it += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++stress_it) + // buffer << *stress_it; + } } /* -------------------------------------------------------------------------- */ -inline void Material::packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const { +inline void Material::unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) { if(tag == _gst_smm_stress) { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); - Vector<Real>::const_iterator<types::Matrix> stress_it = stress(element.type, _not_ghost).begin(spatial_dimension, spatial_dimension); - stress_it += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++stress_it) - buffer << *stress_it; + unpackElementDataHelper(stress, buffer, elements); + // UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); + // Vector<Real>::iterator<types::Matrix> stress_it = stress(element.type, _ghost).begin(spatial_dimension, spatial_dimension); + // stress_it += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++stress_it) + // buffer >> *stress_it; } } /* -------------------------------------------------------------------------- */ -inline void Material::unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) { - if(tag == _gst_smm_stress) { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); - Vector<Real>::iterator<types::Matrix> stress_it = stress(element.type, _ghost).begin(spatial_dimension, spatial_dimension); - stress_it += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++stress_it) - buffer >> *stress_it; +inline UInt Material::getNbQuadraturePoints(const Vector<Element> & elements) const { + UInt nb_quad = 0; + Vector<Element>::const_iterator<Element> it = elements.begin(); + Vector<Element>::const_iterator<Element> end = elements.end(); + for (; it != end; ++it) { + const Element & el = *it; + nb_quad += this->model->getFEM().getNbQuadraturePoints(el.type, el.ghost_type); } + return nb_quad; +} + +/* -------------------------------------------------------------------------- */ +template<typename T> +inline void Material::packElementDataHelper(const ByElementTypeVector<T> & data_to_pack, + CommunicationBuffer & buffer, + const Vector<Element> & elements) const { + packUnpackElementDataHelper<T, true>(const_cast<ByElementTypeVector<T> &>(data_to_pack), + buffer, + elements); } +/* -------------------------------------------------------------------------- */ +template<typename T> +inline void Material::unpackElementDataHelper(ByElementTypeVector<T> & data_to_unpack, + CommunicationBuffer & buffer, + const Vector<Element> & elements) const { + packUnpackElementDataHelper<T, false>(data_to_unpack, buffer, elements); +} + +/* -------------------------------------------------------------------------- */ +template<typename T, bool pack_helper> +inline void Material::packUnpackElementDataHelper(ByElementTypeVector<T> & data_to_pack, + CommunicationBuffer & buffer, + const Vector<Element> & element) const { + ElementType current_element_type = _not_defined; + GhostType current_ghost_type = _casper; + UInt nb_quad_per_elem = 0; + UInt nb_component = 0; + + Vector<T> * vect = NULL; + Vector<UInt> * element_index_material = NULL; + + Vector<Element>::const_iterator<Element> it = element.begin(); + Vector<Element>::const_iterator<Element> end = element.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 = &data_to_pack(el.type, el.ghost_type); + element_index_material = &(this->model->getElementIndexByMaterial(current_element_type, current_ghost_type)); + + nb_quad_per_elem = this->model->getFEM().getNbQuadraturePoints(el.type, el.ghost_type); + nb_component = vect->getNbComponent(); + } + + UInt el_id = (*element_index_material)(el.element); + types::Vector<T> data(vect->storage() + el_id * nb_component * nb_quad_per_elem, + nb_component * nb_quad_per_elem); + if(pack_helper) + buffer << data; + else + buffer >> data; + } +} /* -------------------------------------------------------------------------- */ template <typename T> inline T Material::getParam(const ID & param) const { try { return params.get<T>(param); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << id); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::setParam(const ID & param, T value) { try { params.set<T>(param, value); } catch(...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << id); } updateInternalParameters(); } + +/* -------------------------------------------------------------------------- */ +template<typename T> +void Material::removeQuadraturePointsFromVectors(ByElementTypeVector<T> & data, + const ByElementTypeUInt & new_numbering) { + for(UInt g = _not_ghost; g <= _ghost; ++g) { + GhostType gt = (GhostType) g; + ByElementTypeVector<UInt>::type_iterator it = new_numbering.firstType(0, gt, _ek_not_defined); + ByElementTypeVector<UInt>::type_iterator end = new_numbering.lastType(0, gt, _ek_not_defined); + for (; it != end; ++it) { + ElementType type = *it; + if(data.exists(type, gt)){ + const Vector<UInt> & renumbering = new_numbering(type, gt); + + Vector<T> & vect = data(type, gt); + + UInt nb_quad_per_elem = this->model->getFEM().getNbQuadraturePoints(type, gt); + UInt nb_component = vect.getNbComponent(); + + Vector<T> tmp(renumbering.getSize(), nb_component); + UInt new_size = 0; + for (UInt i = 0; i < vect.getSize(); ++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); + } + } + } +} + /* -------------------------------------------------------------------------- */ inline void Material::onElementsAdded(__attribute__((unused)) const Vector<Element> & element_list) { for (std::map<ID, ByElementTypeReal *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { resizeInternalVector(*(it->second)); } for (std::map<ID, ByElementTypeUInt *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) { resizeInternalVector(*(it->second)); } } + +/* -------------------------------------------------------------------------- */ +inline void Material::onElementsRemoved(const Vector<Element> & element_list, const ByElementTypeUInt & new_numbering) { + ByElementTypeUInt material_local_new_numbering; + initInternalVector(material_local_new_numbering, 1, true); + resizeInternalVector(material_local_new_numbering); + + Vector<Element>::const_iterator<Element> el_begin = element_list.begin(); + Vector<Element>::const_iterator<Element> el_end = element_list.end(); + + for(UInt g = _not_ghost; g <= _ghost; ++g) { + GhostType gt = (GhostType) g; + ByElementTypeVector<UInt>::type_iterator it = new_numbering.firstType(0, gt, _ek_not_defined); + ByElementTypeVector<UInt>::type_iterator end = new_numbering.lastType(0, gt, _ek_not_defined); + for (; it != end; ++it) { + ElementType type = *it; + if(element_filter.exists(type, gt)){ + Vector<UInt> & elem_filter = element_filter(type, gt); + + Vector<UInt> & element_index_material = model->getElementIndexByMaterial(type, gt); + element_index_material.resize(model->getFEM().getMesh().getNbElement(type, gt)); // all materials will resize of the same size... + + Vector<UInt> & mat_renumbering = material_local_new_numbering(type, gt); + Vector<UInt> elem_filter_tmp; + UInt ni; + Element el; + el.type = type; + el.ghost_type = gt; + for (UInt i = 0; i < elem_filter.getSize(); ++i) { + el.element = elem_filter(i); + if(std::find(el_begin, el_end, el) == el_end) { + elem_filter_tmp.push_back(elem_filter(i)); + mat_renumbering(i) = ni; + element_index_material(el.element) = ni; + ++ni; + } else { + mat_renumbering(i) = UInt(-1); + } + } + + elem_filter.resize(elem_filter_tmp.getSize()); + elem_filter.copy(elem_filter); + } + } + } + + for (std::map<ID, ByElementTypeReal *>::iterator it = internal_vectors_real.begin(); + it != internal_vectors_real.end(); + ++it) { + this->removeQuadraturePointsFromVectors(*(it->second), material_local_new_numbering); + } + + for (std::map<ID, ByElementTypeUInt *>::iterator it = internal_vectors_uint.begin(); + it != internal_vectors_uint.end(); + ++it) { + this->removeQuadraturePointsFromVectors(*(it->second), material_local_new_numbering); + } +} diff --git a/src/model/solid_mechanics/materials/material_damage/material_damage.cc b/src/model/solid_mechanics/materials/material_damage/material_damage.cc index d338cb5d2..d1472e62e 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_damage.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_damage.cc @@ -1,163 +1,163 @@ /** * @file material_damage.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Chambart <marion.chambart@epfl.ch> * @date Tue Jul 27 11:53:52 2010 * * @brief Specialization of the material class for the damage material * * @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 "material_damage.hh" #include "solid_mechanics_model.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> MaterialDamage<spatial_dimension>::MaterialDamage(SolidMechanicsModel & model, const ID & id) : Material(model, id), MaterialElastic<spatial_dimension>(model, id), damage("damage", id), - dissipated_energy("Dissipated Energy", id), - strain_prev("Previous Strain", id), - stress_prev("Previous Stress", id), - int_sigma("Integral of sigma", id) { + dissipated_energy("dissipated energy", id), + strain_prev("previous strain", id), + stress_prev("previous stress", id), + int_sigma("integral of sigma", id) { AKANTU_DEBUG_IN(); this->is_non_local = false; this->initInternalVector(this->damage, 1); this->initInternalVector(this->dissipated_energy, 1); this->initInternalVector(this->strain_prev, spatial_dimension * spatial_dimension); this->initInternalVector(this->stress_prev, spatial_dimension * spatial_dimension); this->initInternalVector(this->int_sigma, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialDamage<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialElastic<spatial_dimension>::initMaterial(); this->resizeInternalVector(this->damage); this->resizeInternalVector(this->dissipated_energy); this->resizeInternalVector(this->strain_prev); this->resizeInternalVector(this->stress_prev); this->resizeInternalVector(this->int_sigma); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the dissipated energy in each element by a trapezoidal approximation * of * @f$ Ed = \int_0^{\epsilon}\sigma(\omega)d\omega - \frac{1}{2}\sigma:\epsilon@f$ */ template<UInt spatial_dimension> void MaterialDamage<spatial_dimension>::updateDissipatedEnergy(GhostType ghost_type) { // compute the dissipated energy per element const Mesh & mesh = this->model->getFEM().getMesh(); 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 el_type = *it; Vector<Real>::iterator<types::Matrix> sigma = this->stress(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Vector<Real>::iterator<types::Matrix> sigma_p = stress_prev(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Vector<Real>::iterator<types::Matrix> epsilon = this->strain(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Vector<Real>::iterator<types::Matrix> epsilon_p = strain_prev(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Vector<Real>::iterator<Real> ints = int_sigma(el_type, ghost_type).begin(); Vector<Real>::iterator<Real> ed = dissipated_energy(el_type, ghost_type).begin(); Vector<Real>::iterator<Real> ed_end = dissipated_energy(el_type, ghost_type).end(); for (; ed != ed_end; ++ed, ++ints, ++epsilon, ++sigma, ++epsilon_p, ++sigma_p) { Real epot = 0.; Real dint = 0.; for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { epot += (*sigma)(i,j) * (*epsilon)(i,j); /// \f$ epot = .5 \sigma : \epsilon \f$ dint += .5 * ((*sigma_p)(i,j) + (*sigma)(i,j)) * ((*epsilon)(i,j) - (*epsilon_p)(i,j)); /// \f$ \frac{.5 \sigma(\epsilon(t-h)) + \sigma(\epsilon(t))}{\epsilon(t) - \epsilon(t-h)} \f$ (*epsilon_p)(i,j) = (*epsilon)(i,j); (*sigma_p)(i,j) = (*sigma)(i,j); } } epot *= .5; *ints += dint; *ed = *ints - epot; } } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialDamage<spatial_dimension>::computeAllStresses(GhostType ghost_type) { Material::computeAllStresses(ghost_type); if(!this->is_non_local) this->updateDissipatedEnergy(ghost_type); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> Real MaterialDamage<spatial_dimension>::getDissipatedEnergy() const { AKANTU_DEBUG_IN(); Real de = 0.; const Mesh & mesh = this->model->getFEM().getMesh(); /// integrate the dissipated energy for each type of elements Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost); Mesh::type_iterator end = mesh.lastType(spatial_dimension, _not_ghost); for(; it != end; ++it) { de += this->model->getFEM().integrate(dissipated_energy(*it, _not_ghost), *it, _not_ghost, &this->element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return de; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> Real MaterialDamage<spatial_dimension>::getEnergy(std::string type) { if(type == "dissipated") return getDissipatedEnergy(); else return Material::getEnergy(type); } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialDamage); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_damage/material_damage.hh b/src/model/solid_mechanics/materials/material_damage/material_damage.hh index 9e6dabb57..79e073366 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_damage.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_damage.hh @@ -1,101 +1,104 @@ /** * @file material_damage.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Chambart <marion.chambart@epfl.ch> * @date Thu Jul 29 15:00:59 2010 * * @brief Material isotropic elastic * * @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 "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_DAMAGE_HH__ #define __AKANTU_MATERIAL_DAMAGE_HH__ __BEGIN_AKANTU__ template<UInt spatial_dimension> class MaterialDamage : public MaterialElastic<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialDamage(SolidMechanicsModel & model, const ID & id = ""); virtual ~MaterialDamage() {}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial(); virtual void computeAllStresses(GhostType ghost_type); protected: /// update the dissipated energy, must be called after the stress have been computed void updateDissipatedEnergy(GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// give the dissipated energy for the time step Real getDissipatedEnergy() const; virtual Real getEnergy(std::string type); + AKANTU_GET_MACRO_NOT_CONST(Damage, damage, ByElementTypeReal &); + AKANTU_GET_MACRO(Damage, damage, const ByElementTypeReal &); + /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// damage internal variable ByElementTypeReal damage; /// dissipated energy ByElementTypeReal dissipated_energy; /// previous strain used to compute the dissipated energy ByElementTypeReal strain_prev; /// previous strain used to compute the dissipated energy ByElementTypeReal stress_prev; /// contain the current value of @f$ \int_0^{\epsilon}\sigma(\omega)d\omega @f$ the dissipated energy ByElementTypeReal int_sigma; }; __END_AKANTU__ #endif /* __AKANTU_MATERIAL_DAMAGE_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh b/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh index 94f7b23d8..e53f8bad3 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_damage_non_local.hh @@ -1,136 +1,103 @@ /** * @file material_damage_non_local.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Aug 16 18:28:00 2012 * * @brief interface for non local damage material * * @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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_DAMAGE_NON_LOCAL_HH__ #define __AKANTU_MATERIAL_DAMAGE_NON_LOCAL_HH__ __BEGIN_AKANTU__ template<UInt spatial_dimension, template <UInt> class MaterialDamageLocal, template <UInt> class WeightFunction = BaseWeightFunction> class MaterialDamageNonLocal : public MaterialDamageLocal<spatial_dimension>, public MaterialNonLocal<spatial_dimension, WeightFunction> { public: typedef MaterialNonLocal<spatial_dimension, WeightFunction> MaterialNonLocalParent; typedef MaterialDamageLocal<spatial_dimension> MaterialDamageParent; MaterialDamageNonLocal(SolidMechanicsModel & model, const ID & id) : Material(model, id), MaterialDamageParent(model, id), MaterialNonLocalParent(model, id) { }; /* ------------------------------------------------------------------------ */ virtual void initMaterial() { MaterialDamageParent::initMaterial(); MaterialNonLocalParent::initMaterial(); } protected: /* -------------------------------------------------------------------------- */ virtual void computeNonLocalStress(ElementType type, GhostType ghost_type = _not_ghost) = 0; /* ------------------------------------------------------------------------ */ void computeNonLocalStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = this->model->getFEM().getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = this->model->getFEM().getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { computeNonLocalStress(*it, ghost_type); } this->updateDissipatedEnergy(ghost_type); AKANTU_DEBUG_OUT(); } public: /* ------------------------------------------------------------------------ */ virtual bool parseParam(const std::string & key, const std::string & value, const ID & id) { return MaterialNonLocalParent::parseParam(key, value, id) || MaterialDamageParent::parseParam(key, value, id); } public: /* ------------------------------------------------------------------------ */ - virtual inline UInt getNbDataToPack(const Element & element, - SynchronizationTag tag) const { - return MaterialNonLocalParent::getNbDataToPack(element, tag) + - MaterialDamageParent::getNbDataToPack(element, tag); - } - - virtual inline UInt getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const { - return MaterialNonLocalParent::getNbDataToUnpack(element, tag) + - MaterialDamageParent::getNbDataToUnpack(element, tag); - } - - virtual inline UInt getNbDataToPack(SynchronizationTag tag) const { - return MaterialNonLocalParent::getNbDataToPack(tag) + - MaterialDamageParent::getNbDataToPack(tag); - } - - virtual inline UInt getNbDataToUnpack(SynchronizationTag tag) const { - return MaterialNonLocalParent::getNbDataToUnpack(tag) + - MaterialDamageParent::getNbDataToUnpack(tag); + virtual inline UInt getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const { + return MaterialNonLocalParent::getNbDataForElements(elements, tag) + + MaterialDamageParent::getNbDataForElements(elements, tag); } - - - virtual inline void packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const { - MaterialNonLocalParent::packData(buffer, element, tag); - MaterialDamageParent::packData(buffer, element, tag); + virtual inline void packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const { + MaterialNonLocalParent::packElementData(buffer, elements, tag); + MaterialDamageParent::packElementData(buffer, elements, tag); } - virtual inline void unpackData(CommunicationBuffer & buffer, - const Element & element, + virtual inline void unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, SynchronizationTag tag) { - MaterialNonLocalParent::unpackData(buffer, element, tag); - MaterialDamageParent::unpackData(buffer, element, tag); - } - - virtual void packData(CommunicationBuffer & buffer, - const UInt index, - SynchronizationTag tag) const { - MaterialNonLocalParent::packData(buffer, index, tag); - MaterialDamageParent::packData(buffer, index, tag); + MaterialNonLocalParent::unpackElementData(buffer, elements, tag); + MaterialDamageParent::unpackElementData(buffer, elements, tag); } - virtual void unpackData(CommunicationBuffer & buffer, - const UInt index, - SynchronizationTag tag) { - MaterialNonLocalParent::unpackData(buffer, index, tag); - MaterialDamageParent::unpackData(buffer, index, tag); - } - - }; __END_AKANTU__ #endif /* __AKANTU_MATERIAL_DAMAGE_NON_LOCAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_marigo.hh b/src/model/solid_mechanics/materials/material_damage/material_marigo.hh index 765ea130c..a1e44030c 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_marigo.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_marigo.hh @@ -1,151 +1,139 @@ /** * @file material_marigo.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Chambart <marion.chambart@epfl.ch> * @date Thu Jul 29 15:00:59 2010 * * @brief Material isotropic elastic * * @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 "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_MARIGO_HH__ #define __AKANTU_MATERIAL_MARIGO_HH__ __BEGIN_AKANTU__ /** * Material marigo * * parameters in the material files : * - Yd : (default: 50) * - Sd : (default: 5000) * - Ydrandomness : (default:0) */ template<UInt spatial_dimension> class MaterialMarigo : public MaterialDamage<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialMarigo(SolidMechanicsModel & model, const ID & id = ""); virtual ~MaterialMarigo() {}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial(); virtual void updateInternalParameters(); /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost); protected: /// constitutive law for a given quadrature point inline void computeStressOnQuad(types::Matrix & grad_u, types::Matrix & sigma, Real & dam, Real & Y, Real & Ydq); inline void computeDamageAndStressOnQuad(types::Matrix & sigma, Real & dam, Real & Y, Real & Ydq); /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: - inline virtual UInt getNbDataToPack(const Element & element, - SynchronizationTag tag) const; - - inline virtual UInt getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const; - - inline virtual void packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const; - - inline virtual void unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag); - - virtual UInt getNbDataToPack(__attribute__((unused)) SynchronizationTag tag) const { return 0; } - virtual UInt getNbDataToUnpack(__attribute__((unused)) SynchronizationTag tag) const { return 0; } - virtual void packData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const UInt index, - __attribute__((unused)) SynchronizationTag tag) const { } - virtual void unpackData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const UInt index, - __attribute__((unused)) SynchronizationTag tag) { } + inline virtual UInt getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const; + + inline virtual void packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const; + + inline virtual void unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// resistance to damage Real Yd; /// damage threshold Real Sd; /// randomness on Yd Real Yd_randomness; /// critical epsilon when the material is considered as broken Real epsilon_c; Real Yc; /// Yd random internal variable ByElementTypeReal Yd_rand; bool damage_in_y; bool yc_limit; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_marigo_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_MARIGO_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc b/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc index 8b1a5a078..d942c8da3 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc @@ -1,146 +1,129 @@ /** * @file material_marigo_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Marion Chambart <marion.chambart@epfl.ch> * @date Tue Jul 27 11:57:43 2010 * * @brief Implementation of the inline functions of the material marigo * * @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/>. * */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> inline void MaterialMarigo<spatial_dimension>::computeStressOnQuad(types::Matrix & grad_u, types::Matrix & sigma, Real & dam, Real & Y, Real &Ydq) { MaterialElastic<spatial_dimension>::computeStressOnQuad(grad_u, sigma); Y = 0; for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { Y += sigma(i,j) * grad_u(i,j); } } Y *= 0.5; if(damage_in_y) Y *= (1 - dam); if(yc_limit) Y = std::min(Y, Yc); if(!this->is_non_local) { computeDamageAndStressOnQuad(sigma, dam, Y, Ydq); } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> inline void MaterialMarigo<spatial_dimension>::computeDamageAndStressOnQuad(types::Matrix & sigma, Real & dam, Real & Y, Real &Ydq) { Real Fd = Y - Ydq - Sd * dam; if (Fd > 0) dam = (Y - Ydq) / Sd; dam = std::min(dam,1.); sigma *= 1-dam; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> -inline UInt MaterialMarigo<spatial_dimension>::getNbDataToPack(const Element & element, - SynchronizationTag tag) const { +inline UInt MaterialMarigo<spatial_dimension>::getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if(tag == _gst_smm_init_mat) { - UInt nb_quadrature_points = this->model->getFEM().getNbQuadraturePoints(element.type); - size += sizeof(Real) * nb_quadrature_points; + size += sizeof(Real) * this->getNbQuadraturePoints(elements); } - size += MaterialDamage<spatial_dimension>::getNbDataToPack(element, tag); + size += MaterialDamage<spatial_dimension>::getNbDataForElements(elements, tag); AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> -inline UInt MaterialMarigo<spatial_dimension>::getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const { - AKANTU_DEBUG_IN(); - - UInt size = 0; - if(tag == _gst_smm_init_mat) { - UInt nb_quadrature_points = this->model->getFEM().getNbQuadraturePoints(element.type); - size += sizeof(Real) * nb_quadrature_points; - } - - size += MaterialDamage<spatial_dimension>::getNbDataToPack(element, tag); - - AKANTU_DEBUG_OUT(); - return size; -} - -/* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension> -inline void MaterialMarigo<spatial_dimension>::packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const { +inline void MaterialMarigo<spatial_dimension>::packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const { AKANTU_DEBUG_IN(); if(tag == _gst_smm_init_mat) { - UInt nb_quadrature_points = this->model->getFEM().getNbQuadraturePoints(element.type); - Vector<Real>::const_iterator<Real> Yds = Yd_rand(element.type, _not_ghost).begin(); - Yds += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++Yds) - buffer << *Yds; + this->packElementDataHelper(Yd_rand, buffer, elements); + // UInt nb_quadrature_points = this->model->getFEM().getNbQuadraturePoints(element.type); + // Vector<Real>::const_iterator<Real> Yds = Yd_rand(element.type, _not_ghost).begin(); + // Yds += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++Yds) + // buffer << *Yds; } - MaterialDamage<spatial_dimension>::packData(buffer, element, tag); + MaterialDamage<spatial_dimension>::packElementData(buffer, elements, tag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> -inline void MaterialMarigo<spatial_dimension>::unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) { +inline void MaterialMarigo<spatial_dimension>::unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) { AKANTU_DEBUG_IN(); if(tag == _gst_smm_init_mat) { - UInt nb_quadrature_points = this->model->getFEM().getNbQuadraturePoints(element.type); - Vector<Real>::iterator<Real> Ydr = Yd_rand(element.type, _ghost).begin(); - Ydr += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++Ydr) - buffer << *Ydr; + this->unpackElementDataHelper(Yd_rand, buffer, elements); + // UInt nb_quadrature_points = this->model->getFEM().getNbQuadraturePoints(element.type); + // Vector<Real>::iterator<Real> Ydr = Yd_rand(element.type, _ghost).begin(); + // Ydr += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++Ydr) + // buffer << *Ydr; } - MaterialDamage<spatial_dimension>::unpackData(buffer, element, tag); + MaterialDamage<spatial_dimension>::unpackElementData(buffer, elements, tag); AKANTU_DEBUG_OUT(); } diff --git a/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc b/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc index 58d9b7870..01a37f48c 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc @@ -1,176 +1,176 @@ /** * @file material_mazars_non_local.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marion Chambart <marion.chambart@epfl.ch> * @date Tue Jul 27 11:53:52 2010 * * @brief Specialization of the material class for the non-local mazars material * * @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 "material_mazars_non_local.hh" #include "solid_mechanics_model.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> MaterialMazarsNonLocal<spatial_dimension>::MaterialMazarsNonLocal(SolidMechanicsModel & model, const ID & id) : Material(model, id), MaterialMazars<spatial_dimension>(model, id), MaterialNonLocalParent(model, id), Ehat("epsilon_equ", id) { AKANTU_DEBUG_IN(); this->damage_in_compute_stress = false; this->is_non_local = true; this->initInternalVector(this->Ehat, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialMazars<spatial_dimension>::initMaterial(); MaterialNonLocalParent::initMaterial(); this->resizeInternalVector(this->Ehat); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real * damage = this->damage(el_type, ghost_type).storage(); Real * epsilon_equ = this->Ehat(el_type, ghost_type).storage(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); MaterialMazars<spatial_dimension>::computeStressOnQuad(grad_u, sigma, *damage, *epsilon_equ); ++damage; ++epsilon_equ; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::computeNonLocalStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); ByElementTypeReal nl_var("Non local variable", this->id); - this->initInternalVector(nl_var, 1); + this->initInternalVector(nl_var, 1, true); this->resizeInternalVector(nl_var); if(this->damage_in_compute_stress) this->weightedAvergageOnNeighbours(this->damage, nl_var, 1); else this->weightedAvergageOnNeighbours(this->Ehat, nl_var, 1); Mesh::type_iterator it = this->model->getFEM().getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = this->model->getFEM().getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { this->computeNonLocalStress(nl_var(*it, ghost_type), *it, ghost_type); } this->updateDissipatedEnergy(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::computeNonLocalStress(Vector<Real> & non_loc_var, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real * damage; Real * epsilon_equ; if(this->damage_in_compute_stress){ damage = non_loc_var.storage(); epsilon_equ = this->Ehat(el_type, ghost_type).storage(); } else { damage = this->damage(el_type, ghost_type).storage(); epsilon_equ = non_loc_var.storage(); } MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); this->computeDamageAndStressOnQuad(grad_u, sigma, *damage, *epsilon_equ); ++damage; ++epsilon_equ; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> bool MaterialMazarsNonLocal<spatial_dimension>::parseParam(const std::string & key, const std::string & value, const ID & id) { std::stringstream sstr(value); if(key == "average_on_damage") { sstr >> this->damage_in_compute_stress; } else { return MaterialNonLocalParent::parseParam(key, value, id) || MaterialMazars<spatial_dimension>::parseParam(key, value, id); } return true; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialMazarsNonLocal<spatial_dimension>::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "MaterialMazarsNonLocal [" << std::endl; if(this->damage_in_compute_stress) stream << space << " + Average on damage" << std::endl; else stream << space << " + Average on Ehat" << std::endl; MaterialMazars<spatial_dimension>::printself(stream, indent + 1); MaterialNonLocalParent::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialMazarsNonLocal); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.cc b/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.cc index 4f4ac94fe..234b5f1ab 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.cc +++ b/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.cc @@ -1,207 +1,205 @@ /** * @file material_vreepeerlings.cc * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * @date Fri Feb 17 14:00:00 2012 * * @brief Specialization of the material class for the VreePeerlings material * * @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 "material_vreepeerlings.hh" #include "solid_mechanics_model.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> MaterialVreePeerlings<spatial_dimension>::MaterialVreePeerlings(SolidMechanicsModel & model, const ID & id) : Material(model, id), MaterialDamage<spatial_dimension>(model, id), Kapa("Kapa",id), strain_rate_vreepeerlings("strain-rate-vreepeerlings", id), critical_strain("critical-strain", id) { AKANTU_DEBUG_IN(); this->registerParam("Kapa0i" , Kapa0i , 0.0001, _pat_parsable); this->registerParam("Kapa0" , Kapa0 , 0.0001, _pat_parsable); this->registerParam("Alpha" , Alpha , 0.99 , _pat_parsable); this->registerParam("Beta" , Beta , 300. , _pat_parsable); this->registerParam("Kct" , Kct , 1. , _pat_parsable); this->registerParam("Kapa0_randomness", Kapa0_randomness, 0. , _pat_parsable); firststep = true; countforinitialstep= 0; this->initInternalVector(this->Kapa, 1); this->initInternalVector(this->critical_strain, 1); this->initInternalVector(this->strain_rate_vreepeerlings, spatial_dimension * spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialVreePeerlings<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialDamage<spatial_dimension>::initMaterial(); this->resizeInternalVector(this->Kapa); this->resizeInternalVector(this->critical_strain); this->resizeInternalVector(this->strain_rate_vreepeerlings); const Mesh & mesh = this->model->getFEM().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension); for(; it != last_type; ++it) { Vector <Real>::iterator<Real> kapa_it = Kapa(*it).begin(); Vector <Real>::iterator<Real> kapa_end = Kapa(*it).end(); for(; kapa_it != kapa_end; ++kapa_it) { Real rand_part = (2 * drand48()-1) * Kapa0_randomness * Kapa0i; *kapa_it = Kapa0i + rand_part; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialVreePeerlings<spatial_dimension>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real * dam = this->damage(el_type, ghost_type).storage(); Real * Kapaq = Kapa(el_type, ghost_type).storage(); Real * crit_strain = critical_strain(el_type, ghost_type).storage(); Real dt = this->model->getTimeStep(); Vector<UInt> & elem_filter = this->element_filter(el_type, ghost_type); Vector<Real> & velocity = this->model->getVelocity(); Vector<Real> & strain_rate_vrplgs = this->strain_rate_vreepeerlings(el_type, ghost_type); this->model->getFEM().gradientOnQuadraturePoints(velocity, strain_rate_vrplgs, spatial_dimension, el_type, ghost_type, &elem_filter); Vector<Real>::iterator<types::Matrix> strain_rate_vrplgs_it = strain_rate_vrplgs.begin(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Real Equistrain; Real Equistrain_rate; types::Matrix & strain_rate = *strain_rate_vrplgs_it; computeStressOnQuad(grad_u, sigma, *dam, Equistrain, Equistrain_rate, *Kapaq, dt, strain_rate, *crit_strain); ++dam; ++Kapaq; ++strain_rate_vrplgs_it; ++crit_strain; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; if(!this->is_non_local) this->updateDissipatedEnergy(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension> -UInt MaterialVreePeerlings<spatial_dimension>::getNbDataToPack(const Element & element, - SynchronizationTag tag) const { - AKANTU_DEBUG_IN(); - - UInt size = 0; - if(tag == _gst_smm_init_mat) { - UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); - size += sizeof(Real) + nb_quad; - } - - size += MaterialDamage<spatial_dimension>::getNbDataToPack(element, tag); - - AKANTU_DEBUG_OUT(); - return size; -} - -/* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension> -UInt MaterialVreePeerlings<spatial_dimension>::getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const { - AKANTU_DEBUG_IN(); - - UInt size = 0; - if(tag == _gst_smm_init_mat) { - UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); - size += sizeof(Real) + nb_quad; - } - - size += MaterialDamage<spatial_dimension>::getNbDataToPack(element, tag); - - AKANTU_DEBUG_OUT(); - return size; -} - -/* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension> -void MaterialVreePeerlings<spatial_dimension>::packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const { - AKANTU_DEBUG_IN(); - - if(tag == _gst_smm_init_mat){ - UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); - const Vector<Real> & kapa = Kapa(element.type, _not_ghost); - for(UInt q = 0; q < nb_quad; ++q) - buffer << kapa(element.element * nb_quad + q); - } - - MaterialDamage<spatial_dimension>::packData(buffer, element, tag); - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension> -void MaterialVreePeerlings<spatial_dimension>::unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) { - AKANTU_DEBUG_IN(); - - if(tag == _gst_smm_init_mat) { - UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); - Vector<Real> & kapa = Kapa(element.type, _not_ghost); - for(UInt q = 0; q < nb_quad; ++q) - buffer >> kapa(element.element * nb_quad + q); - } - - MaterialDamage<spatial_dimension>::packData(buffer, element, tag); - AKANTU_DEBUG_OUT(); -} +//UInt MaterialVreePeerlings<spatial_dimension>::getNbDataToPack(const Element & element, +// SynchronizationTag tag) const { +// AKANTU_DEBUG_IN(); +// UInt size = 0; +// if(tag == _gst_smm_init_mat) { +// UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); +// size += sizeof(Real) + nb_quad; +// } + +// size += MaterialDamage<spatial_dimension>::getNbDataToPack(element, tag); + +// AKANTU_DEBUG_OUT(); +// return size; +// } + +// /* -------------------------------------------------------------------------- */ +// template<UInt spatial_dimension> +// UInt MaterialVreePeerlings<spatial_dimension>::getNbDataToUnpack(const Element & element, +// SynchronizationTag tag) const { +// AKANTU_DEBUG_IN(); + +// UInt size = 0; +// if(tag == _gst_smm_init_mat) { +// UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); +// size += sizeof(Real) + nb_quad; +// } + +// size += MaterialDamage<spatial_dimension>::getNbDataToPack(element, tag); + +// AKANTU_DEBUG_OUT(); +// return size; +// } + +// /* -------------------------------------------------------------------------- */ +// template<UInt spatial_dimension> +// void MaterialVreePeerlings<spatial_dimension>::packData(CommunicationBuffer & buffer, +// const Element & element, +// SynchronizationTag tag) const { +// AKANTU_DEBUG_IN(); + +// if(tag == _gst_smm_init_mat){ +// UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); +// const Vector<Real> & kapa = Kapa(element.type, _not_ghost); +// for(UInt q = 0; q < nb_quad; ++q) +// buffer << kapa(element.element * nb_quad + q); +// } + +// MaterialDamage<spatial_dimension>::packData(buffer, element, tag); +// AKANTU_DEBUG_OUT(); +// } + +// /* -------------------------------------------------------------------------- */ +// template<UInt spatial_dimension> +// void MaterialVreePeerlings<spatial_dimension>::unpackData(CommunicationBuffer & buffer, +// const Element & element, +// SynchronizationTag tag) { +// AKANTU_DEBUG_IN(); + +// if(tag == _gst_smm_init_mat) { +// UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(element.type); +// Vector<Real> & kapa = Kapa(element.type, _not_ghost); +// for(UInt q = 0; q < nb_quad; ++q) +// buffer >> kapa(element.element * nb_quad + q); +// } + +// MaterialDamage<spatial_dimension>::packData(buffer, element, tag); +// AKANTU_DEBUG_OUT(); +// } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialVreePeerlings); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.hh b/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.hh index b8015c671..0185d49b5 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_vreepeerlings.hh @@ -1,170 +1,146 @@ /** * @file material_vreepeerlings.hh * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * @date Fri Feb 17 14:00:00 2012 * * @brief Specialization of the material class for the VreePeerlings material * * @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 "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_VREEPEERLINGS_HH__ #define __AKANTU_MATERIAL_VREEPEERLINGS_HH__ __BEGIN_AKANTU__ /** * Material vreepeerlings * * parameters in the material files : * - Kapa0i : (default: 0.0001) Initial threshold (of the equivalent strain) for the initial step * - Kapa0 : (default: 0.0001) Initial threshold (of the equivalent strain) * - Alpha : (default: 0.99) Fitting parameter (must be close to 1 to do tend to 0 the stress in the damaged element) * - Beta : (default: 300) This parameter determines the rate at which the damage grows * - Kct : (default: 1) Ratio between compressive and tensile strength * - Kapa0_randomness : (default:0) Kapa random internal variable */ template<UInt spatial_dimension> class MaterialVreePeerlings : public MaterialDamage<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialVreePeerlings(SolidMechanicsModel & model, const ID & id = ""); virtual ~MaterialVreePeerlings() {}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial(); /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost); protected: /// constitutive law for a given quadrature point inline void computeStressOnQuad(types::Matrix & F, types::Matrix & sigma, Real & dam, Real & Equistrain_rate, Real & Equistrain, Real & Kapaq, Real dt, types::Matrix & strain_rate_vrpgls, Real & crit_strain); inline void computeDamageAndStressOnQuad(types::Matrix & sigma, Real & dam, Real & Equistrain_rate, Real & Equistrain, Real & Kapaq, Real dt, Real & crit_strain); /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: - virtual UInt getNbDataToPack(const Element & element, - SynchronizationTag tag) const; - - virtual UInt getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const; - - virtual void packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const; - - virtual void unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag); - - virtual UInt getNbDataToPack(SynchronizationTag tag) const { return MaterialDamage<spatial_dimension>::getNbDataToPack(tag); } - virtual UInt getNbDataToUnpack(SynchronizationTag tag) const { return MaterialDamage<spatial_dimension>::getNbDataToUnpack(tag); } - virtual void packData(CommunicationBuffer & buffer, - const UInt index, - SynchronizationTag tag) const { MaterialDamage<spatial_dimension>::packData(buffer, index, tag); } - virtual void unpackData(CommunicationBuffer & buffer, - const UInt index, - SynchronizationTag tag) { MaterialDamage<spatial_dimension>::unpackData(buffer, index, tag); } - - /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Initial threshold (of the equivalent strain) (used in the initial step) Real Kapa0i; /// Initial threshold (of the equivalent strain) Real Kapa0; /// Fitting parameter (must be close to 1 to do tend to 0 the stress in the damaged element) Real Alpha; /// This parameter determines the rate at which the damage grows Real Beta; /// Ratio between compressive and tensile strength Real Kct; /// randomness on Kapa0 Real Kapa0_randomness; /// Kapa random internal variable ByElementTypeReal Kapa; /// strain_rate_vreepeerlings ByElementTypeReal strain_rate_vreepeerlings; /// strain_critical_vreepeerlings ByElementTypeReal critical_strain; /// Booleen to check the first step bool firststep; /// counter for initial step Int countforinitialstep; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_vreepeerlings_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_VREEPEERLINGS_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_non_local.hh b/src/model/solid_mechanics/materials/material_non_local.hh index 848387079..7044a9fac 100644 --- a/src/model/solid_mechanics/materials/material_non_local.hh +++ b/src/model/solid_mechanics/materials/material_non_local.hh @@ -1,215 +1,199 @@ /** * @file material_non_local.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Jul 28 11:17:41 2011 * * @brief Material class that handle the non locality of a law for example damage. * * @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 "material.hh" #include "aka_grid.hh" #include "fem.hh" #include "weight_function.hh" namespace akantu { class GridSynchronizer; } /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_NON_LOCAL_HH__ #define __AKANTU_MATERIAL_NON_LOCAL_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt dim, template <UInt> class WeightFunction = BaseWeightFunction> class MaterialNonLocal : public virtual Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialNonLocal(SolidMechanicsModel & model, const ID & id = ""); virtual ~MaterialNonLocal(); template<typename T> class PairList : public ByElementType<ByElementTypeVector<T> > {}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// read properties virtual bool parseParam(const std::string & key, const std::string & value, const ID & id); /// initialize the material computed parameter virtual void initMaterial(); // void computeQuadraturePointsNeighborhoudVolumes(ByElementTypeReal & volumes) const; virtual void updateResidual(GhostType ghost_type); virtual void computeAllNonLocalStresses(GhostType ghost_type = _not_ghost); // void removeDamaged(const ByElementTypeReal & damage, Real thresold); void savePairs(const std::string & filename) const; void neighbourhoodStatistics(const std::string & filename) const; protected: void updatePairList(const ByElementTypeReal & quadrature_points_coordinates); void computeWeights(const ByElementTypeReal & quadrature_points_coordinates); void createCellList(ByElementTypeReal & quadrature_points_coordinates); + void cleanupExtraGhostElement(const ByElementType<UInt> & nb_ghost_protected); + void fillCellList(const ByElementTypeReal & quadrature_points_coordinates, const GhostType & ghost_type); /// constitutive law virtual void computeNonLocalStresses(GhostType ghost_type = _not_ghost) = 0; template<typename T> void weightedAvergageOnNeighbours(const ByElementTypeVector<T> & to_accumulate, ByElementTypeVector<T> & accumulated, UInt nb_degree_of_freedom, GhostType ghost_type2 = _not_ghost) const; // template<typename T> // void accumulateOnNeighbours(const ByElementTypeVector<T> & to_accumulate, // ByElementTypeVector<T> & accumulated, // UInt nb_degree_of_freedom) const; - virtual inline UInt getNbDataToPack(const Element & element, - SynchronizationTag tag) const; - - virtual inline UInt getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const; - - virtual inline void packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const; - - virtual inline void unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag); + virtual inline UInt getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const; - virtual UInt getNbDataToPack(SynchronizationTag tag) const { return Material::getNbDataToPack(tag); } - virtual UInt getNbDataToUnpack(SynchronizationTag tag) const { return Material::getNbDataToUnpack(tag); } - - virtual void packData(CommunicationBuffer & buffer, - const UInt index, - SynchronizationTag tag) const { - Material::packData(buffer, index, tag); - } + virtual inline void packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const; - virtual void unpackData(CommunicationBuffer & buffer, - const UInt index, - SynchronizationTag tag) { - Material::unpackData(buffer, index, tag); - } + virtual inline void unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag); virtual inline void onElementsAdded(const Vector<Element> & element_list); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: void registerNonLocalVariable(ByElementTypeReal & local, ByElementTypeReal & non_local, UInt nb_degree_of_freedom) { ID id = local.getID(); NonLocalVariable & non_local_variable = non_local_variables[id]; non_local_variable.local_variable = &local; non_local_variable.non_local_variable = &non_local; non_local_variable.non_local_variable_nb_component = nb_degree_of_freedom; } AKANTU_GET_MACRO(PairList, pair_list, const PairList<UInt> &) AKANTU_GET_MACRO(Radius, radius, Real); AKANTU_GET_MACRO(CellList, *cell_list, const RegularGrid<QuadraturePoint> &) /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the non local radius Real radius; /// the weight function used WeightFunction<dim> * weight_func; private: /// the pairs of quadrature points PairList<UInt> pair_list; /// the weights associated to the pairs PairList<Real> pair_weight; /// the regular grid to construct/update the pair lists RegularGrid<QuadraturePoint> * cell_list; /// the types of the existing pairs typedef std::set< std::pair<ElementType, ElementType> > pair_type; pair_type existing_pairs[2]; /// specify if the weights should be updated and at which rate UInt update_weights; /// count the number of calls of computeStress UInt compute_stress_calls; struct NonLocalVariable { ByElementTypeVector<Real> * local_variable; ByElementTypeVector<Real> * non_local_variable; UInt non_local_variable_nb_component; }; std::map<ID, NonLocalVariable> non_local_variables; bool is_creating_grid; GridSynchronizer * grid_synchronizer; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_non_local_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_NON_LOCAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc b/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc index 99e7af095..a35e74e0f 100644 --- a/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc @@ -1,761 +1,877 @@ /** * @file material_non_local_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Aug 25 11:59:39 2011 * * @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/>. * */ /* -------------------------------------------------------------------------- */ __END_AKANTU__ /* -------------------------------------------------------------------------- */ #include "aka_types.hh" #include "grid_synchronizer.hh" #include "synchronizer_registry.hh" #include "integrator.hh" /* -------------------------------------------------------------------------- */ #include <iostream> #include <fstream> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt DIM, template <UInt> class WeightFunction> MaterialNonLocal<DIM, WeightFunction>::MaterialNonLocal(SolidMechanicsModel & model, const ID & id) : Material(model, id), radius(100.), weight_func(NULL), cell_list(NULL), update_weights(0), compute_stress_calls(0), is_creating_grid(false), grid_synchronizer(NULL) { AKANTU_DEBUG_IN(); - this->registerParam("radius" , radius , 100., _pat_readable , "Non local radius"); this->registerParam("UpdateWeights" , update_weights, 0U , _pat_modifiable, "Update weights frequency"); this->registerParam("Weight function", weight_func , _pat_internal); this->is_non_local = true; this->weight_func = new WeightFunction<DIM>(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> MaterialNonLocal<spatial_dimension, WeightFunction>::~MaterialNonLocal() { AKANTU_DEBUG_IN(); delete cell_list; delete weight_func; delete grid_synchronizer; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::initMaterial() { AKANTU_DEBUG_IN(); // Material::initMaterial(); Mesh & mesh = this->model->getFEM().getMesh(); ByElementTypeReal quadrature_points_coordinates("quadrature_points_coordinates_tmp_nl", id); - mesh.initByElementTypeVector(quadrature_points_coordinates, spatial_dimension, 0); + this->initInternalVector(quadrature_points_coordinates, spatial_dimension, true); computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); + ByElementType<UInt> nb_ghost_protected; + Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); + Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); + for(; it != last_type; ++it) + nb_ghost_protected(mesh.getNbElement(*it, _ghost), *it, _ghost); + + createCellList(quadrature_points_coordinates); updatePairList(quadrature_points_coordinates); - computeWeights(quadrature_points_coordinates); + + cleanupExtraGhostElement(nb_ghost_protected); weight_func->setRadius(radius); weight_func->init(); - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension, template <UInt> class WeightFunction> -void MaterialNonLocal<spatial_dimension, WeightFunction>::updateResidual(GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - // Update the weights for the non local variable averaging - if(ghost_type == _not_ghost && - this->update_weights && - (this->compute_stress_calls % this->update_weights == 0)) { - ByElementTypeReal quadrature_points_coordinates("quadrature_points_coordinates", id); - Mesh & mesh = this->model->getFEM().getMesh(); - mesh.initByElementTypeVector(quadrature_points_coordinates, spatial_dimension, 0); - computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); - computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); - computeWeights(quadrature_points_coordinates); - } - if(ghost_type == _not_ghost) ++this->compute_stress_calls; - - computeAllStresses(ghost_type); - - computeNonLocalStresses(ghost_type); - assembleResidual(ghost_type); + computeWeights(quadrature_points_coordinates); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> -void MaterialNonLocal<spatial_dimension, WeightFunction>::computeAllNonLocalStresses(GhostType ghost_type) { - // Update the weights for the non local variable averaging - if(ghost_type == _not_ghost) { - if(this->update_weights && (this->compute_stress_calls % this->update_weights == 0)) { - this->model->getSynchronizerRegistry().asynchronousSynchronize(_gst_mnl_weight); +void MaterialNonLocal<spatial_dimension, WeightFunction>::cleanupExtraGhostElement(const ByElementType<UInt> & nb_ghost_protected) { + AKANTU_DEBUG_IN(); - ByElementTypeReal quadrature_points_coordinates("quadrature_points_coordinates", id); - Mesh & mesh = this->model->getFEM().getMesh(); - mesh.initByElementTypeVector(quadrature_points_coordinates, spatial_dimension, 0); - computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); - computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); + // Create list of element to keep + std::set<Element> relevant_ghost_element; - this->model->getSynchronizerRegistry().waitEndSynchronize(_gst_mnl_weight); + pair_type::const_iterator first_pair_types = existing_pairs[1].begin(); + pair_type::const_iterator last_pair_types = existing_pairs[1].end(); + for (; first_pair_types != last_pair_types; ++first_pair_types) { + ElementType type2 = first_pair_types->second; + GhostType ghost_type2 = _ghost; + UInt nb_quad2 = this->model->getFEM().getNbQuadraturePoints(type2); + Vector<UInt> & elem_filter = element_filter(type2, ghost_type2); - computeWeights(quadrature_points_coordinates); + const Vector<UInt> & pairs = + pair_list(first_pair_types->first, _not_ghost)(first_pair_types->second, ghost_type2); + Vector<UInt>::const_iterator< types::Vector<UInt> > first_pair = pairs.begin(2); + Vector<UInt>::const_iterator< types::Vector<UInt> > last_pair = pairs.end(2); + for(;first_pair != last_pair; ++first_pair) { + UInt _q2 = (*first_pair)(1); + QuadraturePoint q2(type2, elem_filter(_q2 / nb_quad2), _q2 % nb_quad2, ghost_type2); + relevant_ghost_element.insert(q2); } + } - typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); - typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); - for(;it != end; ++it) { - NonLocalVariable & non_local_variable = it->second; + // Create list of element to remove and new numbering for element to keep + Mesh & mesh = this->model->getFEM().getMesh(); + std::set<Element> ghost_to_erase; - resizeInternalVector(*non_local_variable.non_local_variable); - this->weightedAvergageOnNeighbours(*non_local_variable.local_variable, *non_local_variable.non_local_variable, - non_local_variable.non_local_variable_nb_component, _not_ghost); - } + Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); + Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); - ++this->compute_stress_calls; - } else { + RemovedElementsEvent remove_elem(mesh); - typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); - typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); - for(;it != end; ++it) { - NonLocalVariable & non_local_variable = it->second; - this->weightedAvergageOnNeighbours(*non_local_variable.local_variable, *non_local_variable.non_local_variable, - non_local_variable.non_local_variable_nb_component, _ghost); + Element element; + element.ghost_type = _ghost; + for(; it != last_type; ++it) { + element.type = *it; + UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); + UInt nb_ghost_elem_protected = 0; + try { + nb_ghost_elem_protected = nb_ghost_protected(*it, _ghost); + } catch (...) {} + + if(!remove_elem.getNewNumbering().exists(*it, _ghost)) + remove_elem.getNewNumbering().alloc(nb_ghost_elem, 1, *it, _ghost); + + Vector<UInt> & elem_filter = element_filter(*it, _ghost); + Vector<UInt> & new_numbering = remove_elem.getNewNumbering(*it, _ghost); + UInt ng = 0; + for (UInt g = 0; g < nb_ghost_elem; ++g) { + element.element = elem_filter(g); + if(element.element >= nb_ghost_elem_protected && + (std::find(relevant_ghost_element.begin(), + relevant_ghost_element.end(), + element) == relevant_ghost_element.end())) { + ghost_to_erase.insert(element); + remove_elem.getList().push_back(element); + + new_numbering(g) = UInt(-1); + } else { + new_numbering(g) = ng; + ++ng; + } } - - computeNonLocalStresses(_not_ghost); } -} -/* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension, template <UInt> class WeightFunction> -template<typename T> -void MaterialNonLocal<spatial_dimension, WeightFunction>::weightedAvergageOnNeighbours(const ByElementTypeVector<T> & to_accumulate, - ByElementTypeVector<T> & accumulated, - UInt nb_degree_of_freedom, - GhostType ghost_type2) const { - AKANTU_DEBUG_IN(); - - UInt existing_pairs_num = 0; - if (ghost_type2 == _ghost) existing_pairs_num = 1; - - pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); - pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); - - GhostType ghost_type1 = _not_ghost; // does not make sens the ghost vs ghost so this should always by _not_ghost + mesh.sendEvent(remove_elem); + // Renumber element to keep + first_pair_types = existing_pairs[1].begin(); + last_pair_types = existing_pairs[1].end(); for (; first_pair_types != last_pair_types; ++first_pair_types) { - const Vector<UInt> & pairs = - pair_list(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); - const Vector<Real> & weights = - pair_weight(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); - - - const Vector<T> & to_acc = to_accumulate(first_pair_types->second, ghost_type2); - Vector<T> & acc = accumulated(first_pair_types->first, ghost_type1); - - Vector<UInt>::const_iterator< types::Vector<UInt> > first_pair = pairs.begin(2); - Vector<UInt>::const_iterator< types::Vector<UInt> > last_pair = pairs.end(2); - Vector<Real>::const_iterator< types::Vector<Real> > pair_w = weights.begin(2); - - for(;first_pair != last_pair; ++first_pair, ++pair_w) { - UInt q1 = (*first_pair)(0); - UInt q2 = (*first_pair)(1); - for(UInt d = 0; d < nb_degree_of_freedom; ++d){ - acc(q1, d) += (*pair_w)(0) * to_acc(q2, d); - if(ghost_type2 != _ghost) acc(q2, d) += (*pair_w)(1) * to_acc(q1, d); - } + ElementType type2 = first_pair_types->second; + GhostType ghost_type2 = _ghost; + UInt nb_quad2 = this->model->getFEM().getNbQuadraturePoints(type2); + + Vector<UInt> & pairs = + pair_list(first_pair_types->first, _not_ghost)(first_pair_types->second, ghost_type2); + Vector<UInt>::iterator< types::Vector<UInt> > first_pair = pairs.begin(2); + Vector<UInt>::iterator< types::Vector<UInt> > last_pair = pairs.end(2); + for(;first_pair != last_pair; ++first_pair) { + UInt _q2 = (*first_pair)(1); + Vector<UInt> & new_numbering = remove_elem.getNewNumbering(type2, ghost_type2); + UInt el = _q2 / nb_quad2; + UInt new_el = new_numbering(el); + (*first_pair)(1) = new_el * nb_quad2 + _q2 % nb_quad2; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::createCellList(ByElementTypeReal & quadrature_points_coordinates) { AKANTU_DEBUG_IN(); const Real safety_factor = 1.2; // for the cell grid spacing Mesh & mesh = this->model->getFEM().getMesh(); mesh.computeBoundingBox(); Real lower_bounds[spatial_dimension]; Real upper_bounds[spatial_dimension]; mesh.getLocalLowerBounds(lower_bounds); mesh.getLocalUpperBounds(upper_bounds); Real spacing[spatial_dimension]; for (UInt i = 0; i < spatial_dimension; ++i) { spacing[i] = radius * safety_factor; } cell_list = new RegularGrid<QuadraturePoint>(spatial_dimension, lower_bounds, upper_bounds, spacing); fillCellList(quadrature_points_coordinates, _not_ghost); is_creating_grid = true; SynchronizerRegistry & synch_registry = this->model->getSynchronizerRegistry(); std::stringstream sstr; sstr << id << ":grid_synchronizer"; grid_synchronizer = GridSynchronizer::createGridSynchronizer(mesh, *cell_list, sstr.str()); synch_registry.registerSynchronizer(*grid_synchronizer, _gst_mnl_for_average); synch_registry.registerSynchronizer(*grid_synchronizer, _gst_mnl_weight); is_creating_grid = false; this->computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); fillCellList(quadrature_points_coordinates, _ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::fillCellList(const ByElementTypeReal & quadrature_points_coordinates, const GhostType & ghost_type) { Mesh & mesh = this->model->getFEM().getMesh(); - QuadraturePoint q; - Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); - Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); + QuadraturePoint q; q.ghost_type = ghost_type; + + 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) { Vector<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_quad = this->model->getFEM().getNbQuadraturePoints(*it, ghost_type); const Vector<Real> & quads = quadrature_points_coordinates(*it, ghost_type); q.type = *it; Vector<Real>::const_iterator<types::RVector> quad = quads.begin(spatial_dimension); UInt * elem = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e) { q.element = *elem; for (UInt nq = 0; nq < nb_quad; ++nq) { q.num_point = nq; q.setPosition(*quad); cell_list->insert(q, *quad); ++quad; } ++elem; } } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::updatePairList(const ByElementTypeReal & quadrature_points_coordinates) { AKANTU_DEBUG_IN(); Mesh & mesh = this->model->getFEM().getMesh(); GhostType ghost_type = _not_ghost; // generate the pair of neighbor depending of the cell_list 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) { // Preparing datas const Vector<Real> & quads = quadrature_points_coordinates(*it, ghost_type); Vector<Real>::const_iterator<types::RVector> first_quad = quads.begin(spatial_dimension); Vector<Real>::const_iterator<types::RVector> last_quad = quads.end(spatial_dimension); ByElementTypeUInt & pairs = pair_list(ByElementTypeUInt("pairs", id, memory_id), *it, ghost_type); ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt existing_pairs_num = 0; Vector<UInt> * neighbors = NULL; + Vector<UInt> * element_index_material2 = NULL; + //Vector<UInt> & element_index_material1 = this->model->getElementIndexByMaterial(*it, ghost_type); UInt my_num_quad = 0; // loop over quad points for(;first_quad != last_quad; ++first_quad, ++my_num_quad) { RegularGrid<QuadraturePoint>::Cell cell = cell_list->getCell(*first_quad); RegularGrid<QuadraturePoint>::neighbor_cells_iterator first_neigh_cell = cell_list->beginNeighborCells(cell); RegularGrid<QuadraturePoint>::neighbor_cells_iterator last_neigh_cell = cell_list->endNeighborCells(cell); // loop over neighbors cells of the one containing the current quadrature // point for (; first_neigh_cell != last_neigh_cell; ++first_neigh_cell) { RegularGrid<QuadraturePoint>::iterator first_neigh_quad = cell_list->beginCell(*first_neigh_cell); RegularGrid<QuadraturePoint>::iterator last_neigh_quad = cell_list->endCell(*first_neigh_cell); // loop over the quadrature point in the current cell of the cell list for (;first_neigh_quad != last_neigh_quad; ++first_neigh_quad){ QuadraturePoint & quad = *first_neigh_quad; UInt nb_quad_per_elem = this->model->getFEM().getNbQuadraturePoints(quad.type, quad.ghost_type); - UInt neigh_num_quad = quad.element * nb_quad_per_elem + quad.num_point; // little optimization to not search in the map at each quad points if(quad.type != current_element_type || quad.ghost_type != current_ghost_type) { - // neigh_quad_positions = quadrature_points_coordinates(quad.type, - // quad.ghost_type).storage(); current_element_type = quad.type; current_ghost_type = quad.ghost_type; existing_pairs_num = quad.ghost_type == _not_ghost ? 0 : 1; if(!pairs.exists(current_element_type, current_ghost_type)) { neighbors = &(pairs.alloc(0, 2, current_element_type, current_ghost_type)); } else { neighbors = &(pairs(current_element_type, current_ghost_type)); } existing_pairs[existing_pairs_num].insert(std::pair<ElementType, ElementType>(*it, current_element_type)); + element_index_material2 = &(this->model->getElementIndexByMaterial(current_element_type, current_ghost_type)); } - // types::RVector neigh_quad(neigh_quad_positions + neigh_num_quad * spatial_dimension, - // spatial_dimension); + UInt neigh_num_quad = (*element_index_material2)(quad.element) * nb_quad_per_elem + + quad.num_point; const types::RVector & neigh_quad = quad.getPosition(); Real distance = first_quad->distance(neigh_quad); if(distance <= radius && (current_ghost_type == _ghost || (current_ghost_type == _not_ghost && my_num_quad <= neigh_num_quad))) { // sotring only half lists UInt pair[2]; pair[0] = my_num_quad; pair[1] = neigh_num_quad; neighbors->push_back(pair); } - // } + } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::computeWeights(const ByElementTypeReal & quadrature_points_coordinates) { AKANTU_DEBUG_IN(); GhostType ghost_type1; ghost_type1 = _not_ghost; ByElementTypeReal quadrature_points_volumes("quadrature_points_volumes", id, memory_id); - this->model->getFEM().getMesh().initByElementTypeVector(quadrature_points_volumes, 1, 0); + this->initInternalVector(quadrature_points_volumes, 1, true); resizeInternalVector(quadrature_points_volumes); const ByElementTypeReal & jacobians_by_type = this->model->getFEM().getIntegratorInterface().getJacobians(); weight_func->updateInternals(quadrature_points_volumes); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; UInt existing_pairs_num = gt - _not_ghost; pair_type::iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); pair_type::iterator last_pair_types = existing_pairs[existing_pairs_num].end(); // Compute the weights for (; first_pair_types != last_pair_types; ++first_pair_types) { ElementType type1 = first_pair_types->first; ElementType type2 = first_pair_types->second; const Vector<UInt> & pairs = pair_list(type1, ghost_type1)(type2, ghost_type2); std::string ghost_id = ""; if (ghost_type1 == _ghost) ghost_id = ":ghost"; ByElementTypeReal & weights_type_1 = pair_weight(type1, ghost_type1); std::stringstream sstr; sstr << id << ":pair_weight:" << type1 << ghost_id; weights_type_1.setID(sstr.str()); Vector<Real> * tmp_weight = NULL; if(!weights_type_1.exists(type2, ghost_type2)) { tmp_weight = &(weights_type_1.alloc(0, 2, type2, ghost_type2)); } else { tmp_weight = &(weights_type_1(type2, ghost_type2)); } Vector<Real> & weights = *tmp_weight; weights.resize(pairs.getSize()); weights.clear(); const Vector<Real> & jacobians_1 = jacobians_by_type(type1, ghost_type1); const Vector<Real> & jacobians_2 = jacobians_by_type(type2, ghost_type2); - // const Vector<UInt> & elem_filter1 = element_filter(type1, ghost_type1); - // const Vector<UInt> & elem_filter2 = element_filter(type2, ghost_type2); UInt nb_quad1 = this->model->getFEM().getNbQuadraturePoints(type1); UInt nb_quad2 = this->model->getFEM().getNbQuadraturePoints(type2); - // UInt nb_tot_quad1 = nb_quad1 * elem_filter1.getSize();; - // UInt nb_tot_quad2 = nb_quad2 * elem_filter2.getSize();; Vector<Real> & quads_volumes1 = quadrature_points_volumes(type1, ghost_type1); Vector<Real> & quads_volumes2 = quadrature_points_volumes(type2, ghost_type2); Vector<Real>::const_iterator<types::RVector> iquads1; Vector<Real>::const_iterator<types::RVector> iquads2; iquads1 = quadrature_points_coordinates(type1, ghost_type1).begin(spatial_dimension); iquads2 = quadrature_points_coordinates(type2, ghost_type2).begin(spatial_dimension); Vector<UInt>::const_iterator< types::Vector<UInt> > first_pair = pairs.begin(2); Vector<UInt>::const_iterator< types::Vector<UInt> > last_pair = pairs.end(2); Vector<Real>::iterator<types::RVector> weight = weights.begin(2); this->weight_func->selectType(type1, ghost_type1, type2, ghost_type2); // Weight function for(;first_pair != last_pair; ++first_pair, ++weight) { UInt _q1 = (*first_pair)(0); UInt _q2 = (*first_pair)(1); const types::RVector & pos1 = iquads1[_q1]; const types::RVector & pos2 = iquads2[_q2]; QuadraturePoint q1(_q1 / nb_quad1, _q1 % nb_quad1, _q1, pos1, type1, ghost_type1); QuadraturePoint q2(_q2 / nb_quad2, _q2 % nb_quad2, _q2, pos2, type2, ghost_type2); Real r = pos1.distance(pos2); Real w2J2 = jacobians_2(_q2); (*weight)(0) = w2J2 * this->weight_func->operator()(r, q1, q2); if(ghost_type2 != _ghost && _q1 != _q2) { Real w1J1 = jacobians_1(_q1); (*weight)(1) = w1J1 * this->weight_func->operator()(r, q2, q1); } else (*weight)(1) = 0; quads_volumes1(_q1) += (*weight)(0); if(ghost_type2 != _ghost) quads_volumes2(_q2) += (*weight)(1); } } } //normalize the weights for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; UInt existing_pairs_num = gt - _not_ghost; pair_type::iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); pair_type::iterator last_pair_types = existing_pairs[existing_pairs_num].end(); first_pair_types = existing_pairs[existing_pairs_num].begin(); for (; first_pair_types != last_pair_types; ++first_pair_types) { ElementType type1 = first_pair_types->first; ElementType type2 = first_pair_types->second; const Vector<UInt> & pairs = pair_list(type1, ghost_type1)(type2, ghost_type2); Vector<Real> & weights = pair_weight(type1, ghost_type1)(type2, ghost_type2); Vector<Real> & quads_volumes1 = quadrature_points_volumes(type1, ghost_type1); Vector<Real> & quads_volumes2 = quadrature_points_volumes(type2, ghost_type2); Vector<UInt>::const_iterator< types::Vector<UInt> > first_pair = pairs.begin(2); Vector<UInt>::const_iterator< types::Vector<UInt> > last_pair = pairs.end(2); Vector<Real>::iterator<types::RVector> weight = weights.begin(2); for(;first_pair != last_pair; ++first_pair, ++weight) { UInt q1 = (*first_pair)(0); UInt q2 = (*first_pair)(1); (*weight)(0) *= 1. / quads_volumes1(q1); if(ghost_type2 != _ghost) (*weight)(1) *= 1. / quads_volumes2(q2); } } } AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +template<UInt spatial_dimension, template <UInt> class WeightFunction> +template<typename T> +void MaterialNonLocal<spatial_dimension, WeightFunction>::weightedAvergageOnNeighbours(const ByElementTypeVector<T> & to_accumulate, + ByElementTypeVector<T> & accumulated, + UInt nb_degree_of_freedom, + GhostType ghost_type2) const { + AKANTU_DEBUG_IN(); + + UInt existing_pairs_num = 0; + if (ghost_type2 == _ghost) existing_pairs_num = 1; + + pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); + pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); + + GhostType ghost_type1 = _not_ghost; // does not make sens the ghost vs ghost so this should always by _not_ghost + + for (; first_pair_types != last_pair_types; ++first_pair_types) { + const Vector<UInt> & pairs = + pair_list(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); + const Vector<Real> & weights = + pair_weight(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); + + + const Vector<T> & to_acc = to_accumulate(first_pair_types->second, ghost_type2); + Vector<T> & acc = accumulated(first_pair_types->first, ghost_type1); + + if(ghost_type2 == _not_ghost) acc.clear(); + + Vector<UInt>::const_iterator< types::Vector<UInt> > first_pair = pairs.begin(2); + Vector<UInt>::const_iterator< types::Vector<UInt> > last_pair = pairs.end(2); + Vector<Real>::const_iterator< types::Vector<Real> > pair_w = weights.begin(2); + + for(;first_pair != last_pair; ++first_pair, ++pair_w) { + UInt q1 = (*first_pair)(0); + UInt q2 = (*first_pair)(1); + for(UInt d = 0; d < nb_degree_of_freedom; ++d){ + acc(q1, d) += (*pair_w)(0) * to_acc(q2, d); + if(ghost_type2 != _ghost) acc(q2, d) += (*pair_w)(1) * to_acc(q1, d); + } + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template<UInt spatial_dimension, template <UInt> class WeightFunction> +void MaterialNonLocal<spatial_dimension, WeightFunction>::updateResidual(GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + // Update the weights for the non local variable averaging + if(ghost_type == _not_ghost && + this->update_weights && + (this->compute_stress_calls % this->update_weights == 0)) { + ByElementTypeReal quadrature_points_coordinates("quadrature_points_coordinates", id); + Mesh & mesh = this->model->getFEM().getMesh(); + mesh.initByElementTypeVector(quadrature_points_coordinates, spatial_dimension, 0); + computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); + computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); + computeWeights(quadrature_points_coordinates); + } + if(ghost_type == _not_ghost) ++this->compute_stress_calls; + + computeAllStresses(ghost_type); + + computeNonLocalStresses(ghost_type); + assembleResidual(ghost_type); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template<UInt spatial_dimension, template <UInt> class WeightFunction> +void MaterialNonLocal<spatial_dimension, WeightFunction>::computeAllNonLocalStresses(GhostType ghost_type) { + // Update the weights for the non local variable averaging + if(ghost_type == _not_ghost) { + if(this->update_weights && (this->compute_stress_calls % this->update_weights == 0)) { + this->model->getSynchronizerRegistry().asynchronousSynchronize(_gst_mnl_weight); + + ByElementTypeReal quadrature_points_coordinates("quadrature_points_coordinates", id); + Mesh & mesh = this->model->getFEM().getMesh(); + mesh.initByElementTypeVector(quadrature_points_coordinates, spatial_dimension, 0); + computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); + computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); + + this->model->getSynchronizerRegistry().waitEndSynchronize(_gst_mnl_weight); + + computeWeights(quadrature_points_coordinates); + } + + typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); + typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); + for(;it != end; ++it) { + NonLocalVariable & non_local_variable = it->second; + + resizeInternalVector(*non_local_variable.non_local_variable); + this->weightedAvergageOnNeighbours(*non_local_variable.local_variable, *non_local_variable.non_local_variable, + non_local_variable.non_local_variable_nb_component, _not_ghost); + } + + ++this->compute_stress_calls; + } else { + + typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); + typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); + for(;it != end; ++it) { + NonLocalVariable & non_local_variable = it->second; + this->weightedAvergageOnNeighbours(*non_local_variable.local_variable, *non_local_variable.non_local_variable, + non_local_variable.non_local_variable_nb_component, _ghost); + } + + computeNonLocalStresses(_not_ghost); + } +} + /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> bool MaterialNonLocal<spatial_dimension, WeightFunction>::parseParam(const std::string & key, const std::string & value, __attribute__((unused)) const ID & id) { std::stringstream sstr(value); if(key == "radius") { sstr >> radius; } else if(key == "UpdateWeights") { sstr >> update_weights; } else if(!weight_func->parseParam(key, value)) return Material::parseParam(key, value, id); return true; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::savePairs(const std::string & filename) const { std::ofstream pout; std::stringstream sstr; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); GhostType ghost_type1; ghost_type1 = _not_ghost; for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; UInt existing_pairs_num = gt - _not_ghost; pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); for (; first_pair_types != last_pair_types; ++first_pair_types) { const Vector<UInt> & pairs = pair_list(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); const Vector<Real> & weights = pair_weight(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); pout << "Types : " << first_pair_types->first << " (" << ghost_type1 << ") - " << first_pair_types->second << " (" << ghost_type2 << ")" << std::endl; Vector<UInt>::const_iterator< types::Vector<UInt> > first_pair = pairs.begin(2); Vector<UInt>::const_iterator< types::Vector<UInt> > last_pair = pairs.end(2); Vector<Real>::const_iterator<types::RVector> pair_w = weights.begin(2); for(;first_pair != last_pair; ++first_pair, ++pair_w) { UInt q1 = (*first_pair)(0); UInt q2 = (*first_pair)(1); pout << q1 << " " << q2 << " "<< (*pair_w)(0) << " " << (*pair_w)(1) << std::endl; } } } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::neighbourhoodStatistics(const std::string & filename) const { std::ofstream pout; pout.open(filename.c_str()); const Mesh & mesh = this->model->getFEM().getMesh(); GhostType ghost_type1; ghost_type1 = _not_ghost; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; UInt existing_pairs_num = gt - _not_ghost; ByElementTypeUInt nb_neighbors("nb_neighbours", id, memory_id); mesh.initByElementTypeVector(nb_neighbors, 1, spatial_dimension); resizeInternalVector(nb_neighbors); pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); for (; first_pair_types != last_pair_types; ++first_pair_types) { const Vector<UInt> & pairs = pair_list(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); if(prank == 0) { pout << ghost_type2 << " "; pout << "Types : " << first_pair_types->first << " " << first_pair_types->second << std::endl; } Vector<UInt>::const_iterator< types::Vector<UInt> > first_pair = pairs.begin(2); Vector<UInt>::const_iterator< types::Vector<UInt> > last_pair = pairs.end(2); Vector<UInt> & nb_neigh_1 = nb_neighbors(first_pair_types->first, ghost_type1); Vector<UInt> & nb_neigh_2 = nb_neighbors(first_pair_types->second, ghost_type2); for(;first_pair != last_pair; ++first_pair) { UInt q1 = (*first_pair)(0); UInt q2 = (*first_pair)(1); ++(nb_neigh_1(q1)); if(q1 != q2) ++(nb_neigh_2(q2)); } } Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type1); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type1); UInt nb_quads = 0; Real sum_nb_neig = 0; UInt max_nb_neig = 0; UInt min_nb_neig = std::numeric_limits<UInt>::max(); for(; it != last_type; ++it) { Vector<UInt> & nb_neighor = nb_neighbors(*it, ghost_type1); Vector<UInt>::iterator<UInt> nb_neigh = nb_neighor.begin(); Vector<UInt>::iterator<UInt> end_neigh = nb_neighor.end(); for (; nb_neigh != end_neigh; ++nb_neigh, ++nb_quads) { UInt nb = *nb_neigh; sum_nb_neig += nb; max_nb_neig = std::max(max_nb_neig, nb); min_nb_neig = std::min(min_nb_neig, nb); } } comm.allReduce(&nb_quads, 1, _so_sum); comm.allReduce(&sum_nb_neig, 1, _so_sum); comm.allReduce(&max_nb_neig, 1, _so_max); comm.allReduce(&min_nb_neig, 1, _so_min); if(prank == 0) { pout << ghost_type2 << " "; pout << "Nb quadrature points: " << nb_quads << std::endl; Real mean_nb_neig = sum_nb_neig / Real(nb_quads); pout << ghost_type2 << " "; pout << "Average nb neighbors: " << mean_nb_neig << "(" << sum_nb_neig << ")" << std::endl; pout << ghost_type2 << " "; pout << "Max nb neighbors: " << max_nb_neig << std::endl; pout << ghost_type2 << " "; pout << "Min nb neighbors: " << min_nb_neig << std::endl; } } pout.close(); } /* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -template<UInt spatial_dimension, template <UInt> class WeightFunction> -inline UInt MaterialNonLocal<spatial_dimension, WeightFunction>::getNbDataToPack(const Element & element, - SynchronizationTag tag) const { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); - if(tag == _gst_mnl_for_average) { - typename std::map<ID, NonLocalVariable>::const_iterator it = non_local_variables.begin(); - typename std::map<ID, NonLocalVariable>::const_iterator end = non_local_variables.end(); - UInt size = 0; - for(;it != end; ++it) { - const NonLocalVariable & non_local_variable = it->second; - size += non_local_variable.non_local_variable_nb_component; - } - return size * sizeof(Real) * nb_quadrature_points; - } else if(tag == _gst_mnl_weight) return weight_func->getNbData(element, tag); - return 0; -} +// template<UInt spatial_dimension, template <UInt> class WeightFunction> +// inline UInt MaterialNonLocal<spatial_dimension, WeightFunction>::getNbDataToPack(const Element & element, +// SynchronizationTag tag) const { +// UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); +// UInt size = 0; +// if(tag == _gst_mnl_for_average) { +// typename std::map<ID, NonLocalVariable>::const_iterator it = non_local_variables.begin(); +// typename std::map<ID, NonLocalVariable>::const_iterator end = non_local_variables.end(); + +// for(;it != end; ++it) { +// const NonLocalVariable & non_local_variable = it->second; +// size += non_local_variable.non_local_variable_nb_component * sizeof(Real) * nb_quadrature_points; +// } +// } + +// size += weight_func->getNbData(element, tag); + +// return size; +// } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> -inline UInt MaterialNonLocal<spatial_dimension, WeightFunction>::getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); +inline UInt MaterialNonLocal<spatial_dimension, WeightFunction>::getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const { + UInt nb_quadrature_points = this->getNbQuadraturePoints(elements); + UInt size = 0; + if(tag == _gst_mnl_for_average) { typename std::map<ID, NonLocalVariable>::const_iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::const_iterator end = non_local_variables.end(); - UInt size = 0; + for(;it != end; ++it) { const NonLocalVariable & non_local_variable = it->second; - size += non_local_variable.non_local_variable_nb_component; + size += non_local_variable.non_local_variable_nb_component * sizeof(Real) * nb_quadrature_points; } - return size * sizeof(Real) * nb_quadrature_points; - } else if(tag == _gst_mnl_weight) return weight_func->getNbData(element, tag); - return 0; + } + + size += weight_func->getNbDataForElements(elements, tag); + + return size; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> -inline void MaterialNonLocal<spatial_dimension, WeightFunction>::packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const { +inline void MaterialNonLocal<spatial_dimension, WeightFunction>::packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const { if(tag == _gst_mnl_for_average) { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); + // UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); typename std::map<ID, NonLocalVariable>::const_iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::const_iterator end = non_local_variables.end(); for(;it != end; ++it) { const NonLocalVariable & non_local_variable = it->second; - Vector<Real>::iterator<types::RVector> local_var = (*non_local_variable.local_variable)(element.type, _not_ghost).begin(non_local_variable.non_local_variable_nb_component); - local_var += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++local_var) - buffer << *local_var; + this->packElementDataHelper(*non_local_variable.local_variable, + buffer, elements); + // Vector<Real>::iterator<types::RVector> local_var = (*non_local_variable.local_variable)(element.type, _not_ghost).begin(non_local_variable.non_local_variable_nb_component); + // local_var += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++local_var) + // buffer << *local_var; } - } else if(tag == _gst_mnl_weight) return weight_func->packData(buffer, element, tag); + } + + weight_func->packElementData(buffer, elements, tag); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> -inline void MaterialNonLocal<spatial_dimension, WeightFunction>::unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) { +inline void MaterialNonLocal<spatial_dimension, WeightFunction>::unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) { if(tag == _gst_mnl_for_average) { - UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); + // UInt nb_quadrature_points = model->getFEM().getNbQuadraturePoints(element.type); typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); for(;it != end; ++it) { NonLocalVariable & non_local_variable = it->second; - Vector<Real>::iterator<types::RVector> local_var = - (*non_local_variable.local_variable)(element.type, _ghost).begin(non_local_variable.non_local_variable_nb_component); - local_var += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++local_var) - buffer >> *local_var; + this->unpackElementDataHelper(*non_local_variable.local_variable, + buffer, elements); + // Vector<Real>::iterator<types::RVector> local_var = + // (*non_local_variable.local_variable)(element.type, _ghost).begin(non_local_variable.non_local_variable_nb_component); + // local_var += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++local_var) + // buffer >> *local_var; } - } else if(tag == _gst_mnl_weight) return weight_func->unpackData(buffer, element, tag); + } + + weight_func->unpackElementData(buffer, elements, tag); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> inline void MaterialNonLocal<spatial_dimension, WeightFunction>::onElementsAdded(const Vector<Element> & element_list) { AKANTU_DEBUG_IN(); if(is_creating_grid) { Int my_index = model->getInternalIndexFromID(id); - std::cout << "Toto :" << my_index << std::endl; AKANTU_DEBUG_ASSERT(my_index != -1, "Something horrible happen, the model does not know the material " << id); Vector<Element>::const_iterator<Element> it = element_list.begin(); Vector<Element>::const_iterator<Element> end = element_list.end(); for (; it != end; ++it) { const Element & elem = *it; model->getElementIndexByMaterial(elem.type, elem.ghost_type)(elem.element) = this->addElement(elem.type, elem.element, elem.ghost_type); model->getElementMaterial(elem.type, elem.ghost_type)(elem.element) = UInt(my_index); } } Material::onElementsAdded(element_list); AKANTU_DEBUG_OUT(); } diff --git a/src/model/solid_mechanics/materials/weight_function.hh b/src/model/solid_mechanics/materials/weight_function.hh index 0e10aec12..84c32f95d 100644 --- a/src/model/solid_mechanics/materials/weight_function.hh +++ b/src/model/solid_mechanics/materials/weight_function.hh @@ -1,415 +1,423 @@ /** * @file weight_function.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Mar 8 16:17:00 2012 * * @brief Weight functions for non local materials * * @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_types.hh" #include "solid_mechanics_model.hh" #include <cmath> /* -------------------------------------------------------------------------- */ #include <vector> #ifndef __AKANTU_WEIGHT_FUNCTION_HH__ #define __AKANTU_WEIGHT_FUNCTION_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Normal weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class BaseWeightFunction { public: BaseWeightFunction(Material & material) : material(material) {} virtual ~BaseWeightFunction() {} virtual void init() {}; virtual void updateInternals(__attribute__((unused)) const ByElementTypeReal & quadrature_points_coordinates) {}; /* ------------------------------------------------------------------------ */ inline void setRadius(Real radius) { R = radius; R2 = R * R; } /* ------------------------------------------------------------------------ */ inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, __attribute__((unused)) ElementType type2, __attribute__((unused)) GhostType ghost_type2) { } /* ------------------------------------------------------------------------ */ inline Real operator()(Real r, __attribute__((unused)) QuadraturePoint & q1, __attribute__((unused)) QuadraturePoint & q2) { Real w = 0; if(r <= R) { Real alpha = (1. - r*r / R2); w = alpha * alpha; // *weight = 1 - sqrt(r / radius); } return w; } /* ------------------------------------------------------------------------ */ bool parseParam(__attribute__((unused)) const std::string & key, __attribute__((unused)) const std::string & value) { return false; } /* ------------------------------------------------------------------------ */ virtual void printself(std::ostream & stream) const { stream << "BaseWeightFunction"; } public: - virtual UInt getNbData(__attribute__((unused)) const Element & element, - __attribute__((unused)) SynchronizationTag tag) const { + virtual UInt getNbDataForElements(__attribute__((unused)) const Vector<Element> & elements, + __attribute__((unused)) SynchronizationTag tag) const { return 0; } - virtual inline void packData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const Element & element, - __attribute__((unused)) SynchronizationTag tag) const {} - - virtual inline void unpackData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const Element & element, - __attribute__((unused)) SynchronizationTag tag) {} + virtual inline void packElementData(__attribute__((unused)) CommunicationBuffer & buffer, + __attribute__((unused)) const Vector<Element> & elements, + __attribute__((unused)) SynchronizationTag tag) const {} + virtual inline void unpackElementData(__attribute__((unused)) CommunicationBuffer & buffer, + __attribute__((unused)) const Vector<Element> & elements, + __attribute__((unused)) SynchronizationTag tag) {} protected: Material & material; Real R; Real R2; }; /* -------------------------------------------------------------------------- */ /* Damage weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class DamagedWeightFunction : public BaseWeightFunction<spatial_dimension> { public: DamagedWeightFunction(Material & material) : BaseWeightFunction<spatial_dimension>(material) {} inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_damage = &this->material.getVector("damage", type2, ghost_type2); } inline Real operator()(Real r, __attribute__((unused)) QuadraturePoint & q1, QuadraturePoint & q2) { UInt quad = q2.global_num; Real D = (*selected_damage)(quad); Real Radius = (1.-D)*(1.-D) * this->R2; if(Radius < Math::getTolerance()) { Radius = 0.01 * 0.01 * this->R2; } Real alpha = std::max(0., 1. - r*r / Radius); Real w = alpha * alpha; return w; } /* ------------------------------------------------------------------------ */ bool parseParam(__attribute__((unused)) const std::string & key, __attribute__((unused)) const std::string & value) { return false; } /* ------------------------------------------------------------------------ */ virtual void printself(std::ostream & stream) const { stream << "DamagedWeightFunction"; } private: const Vector<Real> * selected_damage; }; /* -------------------------------------------------------------------------- */ /* Remove damaged weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class RemoveDamagedWeightFunction : public BaseWeightFunction<spatial_dimension> { public: RemoveDamagedWeightFunction(Material & material) : BaseWeightFunction<spatial_dimension>(material) {} inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_damage = &this->material.getVector("damage", type2, ghost_type2); } inline Real operator()(Real r, __attribute__((unused)) QuadraturePoint & q1, QuadraturePoint & q2) { UInt quad = q2.global_num; if(q1.global_num == quad) return 1.; Real D = (*selected_damage)(quad); Real w = 0.; if(D < damage_limit) { ////alpha2beta6//// // Real alpha = std::max(0., 1. - r*r / this->R2); // w = alpha * alpha * alpha * alpha * alpha * alpha; ////alpha4beta6//// //Real alpha = std::max(0., 1. - (r*r / this->R2)*(r*r / this->R2)); //w = alpha * alpha * alpha * alpha * alpha * alpha; ////alpha6beta6//// //Real alpha = std::max(0., 1. - (r*r / this->R2)*(r*r / this->R2)*(r*r / this->R2)); //w = alpha * alpha * alpha * alpha * alpha * alpha; ////alpha8beta6//// //Real alpha = std::max(0., 1. - (r*r / this->R2)*(r*r / this->R2)*(r*r / this->R2)*(r*r / this->R2)); //w = alpha * alpha * alpha * alpha * alpha * alpha; ////alpha10beta6//// //Real alpha = std::max(0., 1. - (r*r / this->R2)*(r*r / this->R2)*(r*r / this->R2)*(r*r / this->R2)*(r*r / this->R2)); //w = alpha * alpha * alpha * alpha * alpha * alpha; ////alpha2beta2//// Real alpha = std::max(0., 1. - r*r / this->R2); w = alpha * alpha; } - return w; } /* ------------------------------------------------------------------------ */ bool parseParam(const std::string & key, const std::string & value) { std::stringstream sstr(value); if(key == "damage_limit") { sstr >> damage_limit; } else return BaseWeightFunction<spatial_dimension>::parseParam(key, value); return true; } /* ------------------------------------------------------------------------ */ virtual void printself(std::ostream & stream) const { stream << "RemoveDamagedWeightFunction [damage_limit: " << damage_limit << "]"; } - virtual UInt getNbData(const Element & element, - __attribute__((unused)) SynchronizationTag tag) const { - UInt nb_quadrature_points = this->material.getModel().getFEM().getNbQuadraturePoints(element.type); - UInt size = sizeof(Real) * nb_quadrature_points; - return size; - } + virtual UInt getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const { + if(tag == _gst_mnl_weight) + return this->material.getNbQuadraturePoints(elements) * sizeof(Real); - virtual inline void packData(CommunicationBuffer & buffer, - const Element & element, - __attribute__((unused)) SynchronizationTag tag) const { - UInt nb_quadrature_points = this->material.getModel().getFEM().getNbQuadraturePoints(element.type); - const Vector<Real> & dam_vect = this->material.getVector("damage", element.type, _not_ghost); - Vector<Real>::const_iterator<Real> damage = dam_vect.begin(); + return 0; + } - damage += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++damage) - buffer << *damage; + virtual inline void packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const { + if(tag == _gst_mnl_weight) + this->material.packElementDataHelper(dynamic_cast<MaterialDamage<spatial_dimension> &>(this->material).getDamage(), + buffer, + elements); + // UInt nb_quadrature_points = this->material.getModel().getFEM().getNbQuadraturePoints(element.type); + // const Vector<Real> & dam_vect = this->material.getVector("damage", element.type, _not_ghost); + // Vector<Real>::const_iterator<Real> damage = dam_vect.begin(); + + // damage += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++damage) + // buffer << *damage; } - virtual inline void unpackData(CommunicationBuffer & buffer, - const Element & element, - __attribute__((unused)) SynchronizationTag tag) { - UInt nb_quadrature_points = this->material.getModel().getFEM().getNbQuadraturePoints(element.type); - Vector<Real>::iterator<Real> damage = - this->material.getVector("damage", element.type, _ghost).begin(); - damage += element.element * nb_quadrature_points; - for (UInt q = 0; q < nb_quadrature_points; ++q, ++damage) - buffer >> *damage; + virtual inline void unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) { + if(tag == _gst_mnl_weight) + this->material.unpackElementDataHelper(dynamic_cast< MaterialDamage<spatial_dimension> &>(this->material).getDamage(), + buffer, + elements); + + // UInt nb_quadrature_points = this->material.getModel().getFEM().getNbQuadraturePoints(element.type); + // Vector<Real>::iterator<Real> damage = + // this->material.getVector("damage", element.type, _ghost).begin(); + // damage += element.element * nb_quadrature_points; + // for (UInt q = 0; q < nb_quadrature_points; ++q, ++damage) + // buffer >> *damage; } private: /// limit at which a point is considered as complitely broken Real damage_limit; /// internal pointer to the current damage vector const Vector<Real> * selected_damage; }; /* -------------------------------------------------------------------------- */ /* Remove damaged with damage rate weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class RemoveDamagedWithDamageRateWeightFunction : public BaseWeightFunction<spatial_dimension> { public: RemoveDamagedWithDamageRateWeightFunction(Material & material) : BaseWeightFunction<spatial_dimension>(material) {} inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_damage_with_damage_rate = &(this->material.getVector("damage",type2, ghost_type2)); selected_damage_rate_with_damage_rate = &(this->material.getVector("damage-rate",type2, ghost_type2)); } inline Real operator()(Real r, __attribute__((unused)) QuadraturePoint & q1, QuadraturePoint & q2) { UInt quad = q2.global_num; if(q1.global_num == quad) return 1.; Real D = (*selected_damage_with_damage_rate)(quad); Real w = 0.; Real alphaexp = 1.; Real betaexp = 2.; if(D < damage_limit_with_damage_rate) { Real alpha = std::max(0., 1. - pow((r*r / this->R2),alphaexp)); w = pow(alpha, betaexp); } return w; } /* ------------------------------------------------------------------------ */ bool setParam(const std::string & key, const std::string & value) { std::stringstream sstr(value); if(key == "damage_limit") { sstr >> damage_limit_with_damage_rate; } else return BaseWeightFunction<spatial_dimension>::setParam(key, value); return true; } /* ------------------------------------------------------------------------ */ virtual void printself(std::ostream & stream) const { stream << "RemoveDamagedWithDamageRateWeightFunction [damage_limit: " << damage_limit_with_damage_rate << "]"; } private: /// limit at which a point is considered as complitely broken Real damage_limit_with_damage_rate; /// internal pointer to the current damage vector const Vector<Real> * selected_damage_with_damage_rate; /// internal pointer to the current damage rate vector const Vector<Real> * selected_damage_rate_with_damage_rate; }; /* -------------------------------------------------------------------------- */ /* Stress Based Weight */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class StressBasedWeightFunction : public BaseWeightFunction<spatial_dimension> { public: StressBasedWeightFunction(Material & material); void init(); virtual void updateInternals(__attribute__((unused)) const ByElementTypeReal & quadrature_points_coordinates) { updatePrincipalStress(_not_ghost); updatePrincipalStress(_ghost); }; void updatePrincipalStress(GhostType ghost_type); inline void updateQuadraturePointsCoordinates(ByElementTypeReal & quadrature_points_coordinates); inline void selectType(ElementType type1, GhostType ghost_type1, ElementType type2, GhostType ghost_type2); inline Real operator()(Real r, QuadraturePoint & q1, QuadraturePoint & q2); inline Real computeRhoSquare(Real r, types::RVector & eigs, types::Matrix & eigenvects, types::RVector & x_s); /* ------------------------------------------------------------------------ */ bool parseParam(const std::string & key, const std::string & value) { std::stringstream sstr(value); if(key == "ft") { sstr >> ft; } else return BaseWeightFunction<spatial_dimension>::parseParam(key, value); return true; } /* ------------------------------------------------------------------------ */ virtual void printself(std::ostream & stream) const { stream << "StressBasedWeightFunction [ft: " << ft << "]"; } private: Real ft; ByElementTypeReal stress_diag; Vector<Real> * selected_stress_diag; ByElementTypeReal stress_base; Vector<Real> * selected_stress_base; ByElementTypeReal quadrature_points_coordinates; Vector<Real> * selected_position_1; Vector<Real> * selected_position_2; ByElementTypeReal characteristic_size; Vector<Real> * selected_characteristic_size; }; template<UInt spatial_dimension> inline std::ostream & operator <<(std::ostream & stream, const BaseWeightFunction<spatial_dimension> & _this) { _this.printself(stream); return stream; } template<UInt spatial_dimension> inline std::ostream & operator <<(std::ostream & stream, const BaseWeightFunction<spatial_dimension> * _this) { _this->printself(stream); return stream; } template<UInt d> inline std::ostream & operator >>(std::ostream & stream, __attribute__((unused)) const BaseWeightFunction<d> * _this) { AKANTU_DEBUG_TO_IMPLEMENT(); return stream; } template<UInt d> inline std::ostream & operator >>(std::ostream & stream, __attribute__((unused)) const RemoveDamagedWeightFunction<d> * _this) { AKANTU_DEBUG_TO_IMPLEMENT(); return stream; } template<UInt d> inline std::ostream & operator >>(std::ostream & stream, __attribute__((unused)) const DamagedWeightFunction<d> * _this) { AKANTU_DEBUG_TO_IMPLEMENT(); return stream; } template<UInt d> inline std::ostream & operator >>(std::ostream & stream, __attribute__((unused)) const StressBasedWeightFunction<d> * _this) { AKANTU_DEBUG_TO_IMPLEMENT(); return stream; } #include "weight_function_tmpl.hh" __END_AKANTU__ #endif /* __AKANTU_WEIGHT_FUNCTION_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index 46efc559e..f738702f5 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1184 +1,1221 @@ /** * @file solid_mechanics_model.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Jul 22 14:35:38 2010 * * @brief Implementation of the SolidMechanicsModel class * * @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_math.hh" #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "integration_scheme_2nd_order.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" #ifdef AKANTU_USE_MUMPS #include "solver_mumps.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(id, memory_id), time_step(NAN), f_m2a(1.0), mass_matrix(NULL), velocity_damping_matrix(NULL), stiffness_matrix(NULL), jacobian_matrix(NULL), element_material("element_material", id), element_index_by_material("element index by material", id), integrator(NULL), increment_flag(false), solver(NULL), spatial_dimension(dim), mesh(mesh) { AKANTU_DEBUG_IN(); createSynchronizerRegistry(this); if (spatial_dimension == 0) spatial_dimension = mesh.getSpatialDimension(); registerFEMObject<MyFEMType>("SolidMechanicsFEM", mesh, spatial_dimension); this->displacement = NULL; this->mass = NULL; this->velocity = NULL; this->acceleration = NULL; this->force = NULL; this->residual = NULL; this->boundary = NULL; this->increment = NULL; this->increment_acceleration = NULL; this->dof_synchronizer = NULL; materials.clear(); mesh.registerEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { delete *mat_it; } materials.clear(); delete integrator; if(solver) delete solver; if(mass_matrix) delete mass_matrix; if(velocity_damping_matrix) delete velocity_damping_matrix; if(stiffness_matrix && stiffness_matrix != jacobian_matrix) delete stiffness_matrix; if(jacobian_matrix) delete jacobian_matrix; if(dof_synchronizer) delete dof_synchronizer; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilites */ void SolidMechanicsModel::initFull(std::string material_file, AnalysisMethod analysis_method) { method = analysis_method; // initialize the model initModel(); // initialize the vectors initVectors(); // set the initial condition to 0 force->clear(); velocity->clear(); acceleration->clear(); displacement->clear(); // initialize pcb if(pbc_pair.size()!=0) initPBC(); // initialize the time integration schemes switch(method) { case _explicit_dynamic: initExplicit(); break; case _implicit_dynamic: initImplicit(true); break; case _static: initImplicit(false); break; } // initialize the materials if(material_file != "") { readMaterials(material_file); initMaterials(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initParallel(MeshPartition * partition, DataAccessor * data_accessor) { AKANTU_DEBUG_IN(); if (data_accessor == NULL) data_accessor = this; Synchronizer & synch_parallel = createParallelSynch(partition,data_accessor); synch_registry->registerSynchronizer(synch_parallel,_gst_smm_mass); // synch_registry->registerSynchronizer(synch_parallel,_gst_smm_for_strain); synch_registry->registerSynchronizer(synch_parallel,_gst_smm_stress); synch_registry->registerSynchronizer(synch_parallel,_gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initFEMBoundary(bool create_surface) { if(create_surface) MeshUtils::buildFacets(mesh); FEM & fem_boundary = getFEMBoundary(); fem_boundary.initShapeFunctions(); fem_boundary.computeNormalsOnControlPoints(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initExplicit() { AKANTU_DEBUG_IN(); method = _explicit_dynamic; if (integrator) delete integrator; integrator = new CentralDifference(); UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); std::stringstream sstr; sstr << id << ":increment_acceleration"; increment_acceleration = &(alloc<Real>(sstr.str(), nb_nodes, nb_degree_of_freedom, Real())); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Allocate all the needed vectors. By default their are not necessarily set to * 0 * */ void SolidMechanicsModel::initVectors() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":displacement"; std::stringstream sstr_mass; sstr_mass << id << ":mass"; std::stringstream sstr_velo; sstr_velo << id << ":velocity"; std::stringstream sstr_acce; sstr_acce << id << ":acceleration"; std::stringstream sstr_forc; sstr_forc << id << ":force"; std::stringstream sstr_resi; sstr_resi << id << ":residual"; std::stringstream sstr_boun; sstr_boun << id << ":boundary"; displacement = &(alloc<Real>(sstr_disp.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); mass = &(alloc<Real>(sstr_mass.str(), nb_nodes, spatial_dimension, 0)); velocity = &(alloc<Real>(sstr_velo.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); acceleration = &(alloc<Real>(sstr_acce.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); force = &(alloc<Real>(sstr_forc.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); residual = &(alloc<Real>(sstr_resi.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); boundary = &(alloc<bool>(sstr_boun.str(), nb_nodes, spatial_dimension, false)); std::stringstream sstr_curp; sstr_curp << id << ":current_position"; current_position = &(alloc<Real>(sstr_curp.str(), 0, spatial_dimension, REAL_INIT_VALUE)); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, gt); element_material.alloc(nb_element, 1, *it, gt); } } dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian * */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEM().initShapeFunctions(_not_ghost); getFEM().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initPBC() { Model::initPBC(); registerPBCSynchronizer(); // as long as there are ones on the diagonal of the matrix, we can put boudandary true for slaves std::map<UInt, UInt>::iterator it = pbc_pair.begin(); std::map<UInt, UInt>::iterator end = pbc_pair.end(); UInt dim = mesh.getSpatialDimension(); while(it != end) { for (UInt i=0; i<dim; ++i) (*boundary)((*it).first,i) = true; ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::registerPBCSynchronizer(){ PBCSynchronizer * synch = new PBCSynchronizer(pbc_pair); synch_registry->registerSynchronizer(*synch, _gst_smm_uv); synch_registry->registerSynchronizer(*synch, _gst_smm_mass); synch_registry->registerSynchronizer(*synch, _gst_smm_res); changeLocalEquationNumberforPBC(pbc_pair, mesh.getSpatialDimension()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); current_position->resize(nb_nodes); Real * current_position_val = current_position->values; Real * position_val = mesh.getNodes().values; Real * displacement_val = displacement->values; /// compute current_position = initial_position + displacement memcpy(current_position_val, position_val, nb_nodes*spatial_dimension*sizeof(Real)); for (UInt n = 0; n < nb_nodes*spatial_dimension; ++n) { *current_position_val++ += *displacement_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeUpdateResidualData() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); residual->resize(nb_nodes); /// copy the forces in residual for boundary conditions memcpy(residual->values, force->values, nb_nodes*spatial_dimension*sizeof(Real)); updateCurrentPosition(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Explicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * This function compute the second member of the motion equation. That is to * say the sum of forces @f$ r = F_{ext} - F_{int} @f$. @f$ F_{ext} @f$ is given * by the user in the force vector, and @f$ F_{int} @f$ is computed as @f$ * F_{int} = \int_{\Omega} N \sigma d\Omega@f$ * */ void SolidMechanicsModel::updateResidual(bool need_initialize) { AKANTU_DEBUG_IN(); // f = f_ext - f_int // f = f_ext if (need_initialize) initializeUpdateResidualData(); if (method == _explicit_dynamic) { // f -= fint // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); // communicate the displacement // synch_registry->asynchronousSynchronize(_gst_smm_for_strain); std::vector<Material *>::iterator mat_it; // call update residual on each local elements for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } #ifdef AKANTU_DAMAGE_NON_LOCAL /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ synch_registry->asynchronousSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_not_ghost); } synch_registry->waitEndSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_ghost); } #endif /* ------------------------------------------------------------------------ */ /* assembling the forces internal */ // communicate the strain synch_registry->asynchronousSynchronize(_gst_smm_stress); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_not_ghost); } // finalize communications synch_registry->waitEndSynchronize(_gst_smm_stress); // synch_registry->waitEndSynchronize(_gst_smm_for_strain); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_ghost); } } else { // updateSupportReaction(); Vector<Real> * Ku = new Vector<Real>(*displacement, true, "Ku"); *Ku *= *stiffness_matrix; *residual -= *Ku; delete Ku; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ //void SolidMechanicsModel::updateSupportReaction() { // const Vector<Int> & irn = stiffness_matrix->getIRN(); // const Vector<Int> & jcn = stiffness_matrix->getJCN(); // const Vector<Real> & A = stiffness_matrix->getA(); // // Real * residual = residual->storage(); // Real * displacement = displacement->storage(); // bool * boundary = boundary->storage(); // // UInt n = stiffness_matrix->getNbNonZero(); // // for (UInt i = 0; i < n; ++i) { // // } //} /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateResidualInternal() { AKANTU_DEBUG_IN(); // f = f_ext - f_int - Ma - Cv = r - Ma - Cv; if(method != _static) { // f -= Ma if(mass_matrix) { // if full mass_matrix Vector<Real> * Ma = new Vector<Real>(*acceleration, true, "Ma"); *Ma *= *mass_matrix; /// \todo check unit conversion for implicit dynamics // *Ma /= f_m2a *residual -= *Ma; delete Ma; } else { // else lumped mass UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); Real * mass_val = mass->values; Real * accel_val = acceleration->values; Real * res_val = residual->values; bool * boundary_val = boundary->values; for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*boundary_val)) { *res_val -= *accel_val * *mass_val /f_m2a; } boundary_val++; res_val++; mass_val++; accel_val++; } } // f -= Cv if(velocity_damping_matrix) { Vector<Real> * Cv = new Vector<Real>(*velocity); *Cv *= *velocity_damping_matrix; *residual -= *Cv; delete Cv; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateAcceleration() { AKANTU_DEBUG_IN(); updateResidualInternal(); if(method == _explicit_dynamic && !mass_matrix) { /* residual = residual_{n+1} - M * acceleration_n therefore solution = increment acceleration not acceleration */ solveLumped(*increment_acceleration, *mass, *residual, *boundary, f_m2a); } else { solveDynamic<NewmarkBeta::_acceleration_corrector>(*increment_acceleration); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveLumped(Vector<Real> & x, const Vector<Real> & A, const Vector<Real> & b, const Vector<bool> & boundary, Real alpha) { Real * A_val = A.storage(); Real * b_val = b.storage(); Real * x_val = x.storage(); bool * boundary_val = boundary.storage(); UInt nb_degrees_of_freedom = x.getSize() * x.getNbComponent(); for (UInt n = 0; n < nb_degrees_of_freedom; ++n) { if(!(*boundary_val)) { *x_val = alpha * (*b_val / *A_val); } x_val++; A_val++; b_val++; boundary_val++; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitPred() { AKANTU_DEBUG_IN(); if(increment_flag) { memcpy(increment->values, displacement->values, displacement->getSize()*displacement->getNbComponent()*sizeof(Real)); } AKANTU_DEBUG_ASSERT(integrator,"itegrator should have been allocated: " << "have called initExplicit ? " << "or initImplicit ?"); integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *boundary); if(increment_flag) { Real * inc_val = increment->values; Real * dis_val = displacement->values; UInt nb_nodes = displacement->getSize(); for (UInt n = 0; n < nb_nodes; ++n) { *inc_val = *dis_val - *inc_val; inc_val++; dis_val++; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitCorr() { AKANTU_DEBUG_IN(); integrator->integrationSchemeCorrAccel(time_step, *displacement, *velocity, *acceleration, *boundary, *increment_acceleration); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Implicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * Initialize the solver and create the sparse matrices needed. * */ void SolidMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) { #if !defined(AKANTU_USE_MUMPS) // or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake AKANTU_DEBUG_ERROR("You should at least activate one solver."); #else UInt nb_global_node = mesh.getNbGlobalNodes(); std::stringstream sstr; sstr << id << ":jacobian_matrix"; jacobian_matrix = new SparseMatrix(nb_global_node * spatial_dimension, _symmetric, spatial_dimension, sstr.str(), memory_id); // dof_synchronizer->initGlobalDOFEquationNumbers(); jacobian_matrix->buildProfile(mesh, *dof_synchronizer); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solv; sstr_solv << id << ":solver"; solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS solver->initialize(options); #endif //AKANTU_HAS_SOLVER } /* -------------------------------------------------------------------------- */ /** * Initialize the implicit solver, either for dynamic or static cases, * * @param dynamic */ void SolidMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); method = dynamic ? _implicit_dynamic : _static; initSolver(solver_options); if(method == _implicit_dynamic) { if(integrator) delete integrator; integrator = new TrapezoidalRule2(); std::stringstream sstr; sstr << id << ":stiffness_matrix"; stiffness_matrix = new SparseMatrix(*jacobian_matrix, sstr.str(), memory_id); } else { stiffness_matrix = jacobian_matrix; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initialAcceleration() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving Ma = f"); Solver * acc_solver = NULL; std::stringstream sstr; sstr << id << ":tmp_mass_matrix"; SparseMatrix * tmp_mass = new SparseMatrix(*mass_matrix, sstr.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solver; sstr << id << ":solver_mass_matrix"; acc_solver = new SolverMumps(*mass_matrix, sstr_solver.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS acc_solver->initialize(); tmp_mass->applyBoundary(*boundary); acc_solver->setRHS(*residual); acc_solver->solve(*acceleration); delete acc_solver; delete tmp_mass; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); stiffness_matrix->clear(); // call compute stiffness matrix on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->assembleStiffnessMatrix(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveDynamic() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL, "You should first initialize the implicit solver and assemble the stiffness matrix"); AKANTU_DEBUG_ASSERT(mass_matrix != NULL, "You should first initialize the implicit solver and assemble the mass matrix"); if(!increment) setIncrementFlagOn(); updateResidualInternal(); solveDynamic<NewmarkBeta::_displacement_corrector>(*increment); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveStatic() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving Ku = f"); AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL, "You should first initialize the implicit solver and assemble the stiffness matrix"); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent(); stiffness_matrix->applyBoundary(*boundary); if(method != _static) jacobian_matrix->copyContent(*stiffness_matrix); solver->setRHS(*residual); if(!increment) setIncrementFlagOn(); solver->solve(*increment); Real * increment_val = increment->values; Real * displacement_val = displacement->values; bool * boundary_val = boundary->values; for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*boundary_val)) { *displacement_val += *increment_val; } displacement_val++; boundary_val++; increment_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance) { Real error; bool tmp = testConvergenceIncrement(tolerance, error); AKANTU_DEBUG_INFO("Norm of increment : " << error); return tmp; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error) { AKANTU_DEBUG_IN(); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * boundary_val = boundary->storage(); Real * displacement_val = displacement->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*boundary_val) && is_local_node) { norm[0] += *increment_val * *increment_val; norm[1] += *displacement_val * *displacement_val; } boundary_val++; increment_val++; displacement_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum); norm[0] = sqrt(norm[0]); norm[1] = sqrt(norm[1]); AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); error = norm[0] / norm[1]; return (error < tolerance); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance) { Real error; bool tmp = testConvergenceResidual(tolerance, error); AKANTU_DEBUG_INFO("Norm of residual : " << error); return tmp; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->values; bool * boundary_val = boundary->values; for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < spatial_dimension; ++d) { if(!(*boundary_val)) { norm += *residual_val * *residual_val; } boundary_val++; residual_val++; } } else { boundary_val += spatial_dimension; residual_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitPred() { AKANTU_DEBUG_IN(); integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitCorr() { AKANTU_DEBUG_IN(); integrator->integrationSchemeCorrDispl(time_step, *displacement, *velocity, *acceleration, *boundary, *increment); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeBoundaries() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initParallel?"); synch_registry->synchronize(_gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeResidual() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initPBC?"); synch_registry->synchronize(_gst_smm_res); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setIncrementFlagOn() { AKANTU_DEBUG_IN(); if(!increment) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_inc; sstr_inc << id << ":increment"; increment = &(alloc<Real>(sstr_inc.str(), nb_nodes, spatial_dimension, 0)); } increment_flag = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors StaticCommunicator::getStaticCommunicator().allReduce(&min_dt, 1, _so_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Material ** mat_val = &(materials.at(0)); Real min_dt = std::numeric_limits<Real>::max(); Real * coord = mesh.getNodes().values; Real * disp_val = displacement->values; Element elem; elem.ghost_type = ghost_type; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { elem.type = *it; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); UInt nb_element = mesh.getNbElement(*it); UInt * conn = mesh.getConnectivity(*it, ghost_type).storage(); UInt * elem_mat_val = element_material(*it, ghost_type).storage(); Real * u = new Real[nb_nodes_per_element*spatial_dimension]; for (UInt el = 0; el < nb_element; ++el) { UInt el_offset = el * nb_nodes_per_element; elem.element = el; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt offset_conn = conn[el_offset + n] * spatial_dimension; memcpy(u + n * spatial_dimension, coord + offset_conn, spatial_dimension * sizeof(Real)); for (UInt i = 0; i < spatial_dimension; ++i) { u[n * spatial_dimension + i] += disp_val[offset_conn + i]; } } Real el_size = getFEM().getElementInradius(u, *it); Real el_dt = mat_val[elem_mat_val[el]]->getStableTimeStep(el_size, elem); min_dt = min_dt > el_dt ? el_dt : min_dt; } delete [] u; } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real energy = 0.; /// call update residual on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getPotentialEnergy(); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy() { AKANTU_DEBUG_IN(); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); Real * vel_val = velocity->values; Real * mass_val = mass->values; for (UInt n = 0; n < nb_nodes; ++n) { Real mv2 = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !getIsPBCSlaveNode(n); + bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { - // if(is_local_node) { - mv2 += is_local_node * is_not_pbc_slave_node * *vel_val * *vel_val * *mass_val; - // } + mv2 += count_node * *vel_val * *vel_val * *mass_val; + vel_val++; mass_val++; } ekin += mv2; } StaticCommunicator::getStaticCommunicator().allReduce(&ekin, 1, _so_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); Real * velo = velocity->storage(); Real * forc = force->storage(); Real * resi = residual->storage(); bool * boun = boundary->storage(); Real work = 0.; UInt nb_nodes = mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !getIsPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { if(*boun) work -= count_node * *resi * *velo * time_step; else work += count_node * *forc * *velo * time_step; ++velo; ++forc; ++resi; ++boun; } } StaticCommunicator::getStaticCommunicator().allReduce(&work, 1, _so_sum); AKANTU_DEBUG_OUT(); return work; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(std::string id) { AKANTU_DEBUG_IN(); if (id == "kinetic") { return getKineticEnergy(); } else if (id == "external work"){ return getExternalWork(); } Real energy = 0.; std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getEnergy(id); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Vector<UInt> & nodes_list) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if(displacement) displacement->resize(nb_nodes); if(mass ) mass ->resize(nb_nodes); if(velocity ) velocity ->resize(nb_nodes); if(acceleration) acceleration->resize(nb_nodes); if(force ) force ->resize(nb_nodes); if(residual ) residual ->resize(nb_nodes); if(boundary ) boundary ->resize(nb_nodes); if(increment_acceleration) increment_acceleration->resize(nb_nodes); if(increment) increment->resize(nb_nodes); delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onNodesAdded(nodes_list); } if(method != _explicit_dynamic) AKANTU_DEBUG_TO_IMPLEMENT(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Vector<Element> & element_list) { AKANTU_DEBUG_IN(); getFEM().initShapeFunctions(_not_ghost); - getFEM().initShapeFunctions(_ghost); + getFEM().initShapeFunctions(_ghost); Vector<Element>::const_iterator<Element> it = element_list.begin(); Vector<Element>::const_iterator<Element> end = element_list.end(); for (; it != end; ++it) { const Element & elem = *it; element_material(elem.type, elem.ghost_type).push_back(UInt(0)); element_index_by_material(elem.type, elem.ghost_type).push_back(UInt(0)); } std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsAdded(element_list); } if(method != _explicit_dynamic) AKANTU_DEBUG_TO_IMPLEMENT(); AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::onElementsRemoved(const Vector<Element> & element_list, + const ByElementTypeUInt & new_numbering) { + element_material.onElementsRemoved(new_numbering); + // element_index_by_material.onElementsRemoved(new_numbering); + + std::cout << "NbNodes before purify " << mesh.getNbNodes() << std::endl; + // MeshUtils::purifyMesh(mesh); + std::cout << "NbNodes after purify " << mesh.getNbNodes() << std::endl; + + getFEM().initShapeFunctions(_not_ghost); + getFEM().initShapeFunctions(_ghost); + +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::onNodesRemoved(const Vector<UInt> & element_list, + const Vector<UInt> & new_numbering) { + std::cout << "NbNodes in u before purify " << displacement->getSize() << " " << element_list.getSize() << " " << mesh.getNbNodes() << std::endl; + if(displacement) mesh.removeNodesFromVector(*displacement, new_numbering); + std::cout << "NbNodes in u after purify " << displacement->getSize() << std::endl; + if(mass ) mesh.removeNodesFromVector(*mass , new_numbering); + if(velocity ) mesh.removeNodesFromVector(*velocity , new_numbering); + if(acceleration) mesh.removeNodesFromVector(*acceleration, new_numbering); + if(force ) mesh.removeNodesFromVector(*force , new_numbering); + if(residual ) mesh.removeNodesFromVector(*residual , new_numbering); + if(boundary ) mesh.removeNodesFromVector(*boundary , new_numbering); + + if(increment_acceleration) mesh.removeNodesFromVector(*increment_acceleration, new_numbering); + if(increment) mesh.removeNodesFromVector(*increment , new_numbering); + + delete dof_synchronizer; + dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); + dof_synchronizer->initLocalDOFEquationNumbers(); + dof_synchronizer->initGlobalDOFEquationNumbers(); +} + /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEM().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); mass ->printself(stream, indent + 2); velocity ->printself(stream, indent + 2); acceleration->printself(stream, indent + 2); force ->printself(stream, indent + 2); residual ->printself(stream, indent + 2); boundary ->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + connectivity type information [" << std::endl; element_material.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index d34c12dff..58703f48f 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,557 +1,579 @@ /** * @file solid_mechanics_model.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date[creation] Thu Jul 22 11:51:06 2010 * @date[last modification] Thu Oct 14 14:00:06 2010 * * @brief Model of Solid Mechanics * * @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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "model.hh" #include "data_accessor.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "integrator_cohesive.hh" #include "shape_cohesive.hh" #include "aka_types.hh" #include "integration_scheme_2nd_order.hh" #include "solver.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Material; class IntegrationScheme2ndOrder; class Contact; class SparseMatrix; } __BEGIN_AKANTU__ class SolidMechanicsModel : public Model, public DataAccessor, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef FEMTemplate<IntegratorGauss,ShapeLagrange> MyFEMType; typedef FEMTemplate< IntegratorCohesive<IntegratorGauss>, ShapeCohesive<ShapeLagrange> > MyFEMCohesiveType; SolidMechanicsModel(Mesh & mesh, UInt spatial_dimension = 0, const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize completely the model virtual void initFull(std::string material_file, AnalysisMethod method = _explicit_dynamic); /// initialize the fem object needed for boundary conditions void initFEMBoundary(bool create_surface = true); /// register the tags associated with the parallel synchronizer void initParallel(MeshPartition * partition, DataAccessor * data_accessor=NULL); /// allocate all vectors void initVectors(); /// initialize all internal arrays for materials void initMaterials(); /// initialize the model virtual void initModel(); /// init PBC synchronizer void initPBC(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* PBC */ /* ------------------------------------------------------------------------ */ public: /// change the equation number for proper assembly when using PBC void changeEquationNumberforPBC(std::map<UInt,UInt> & pbc_pair); /// synchronize Residual for output void synchronizeResidual(); protected: /// register PBC synchronizer void registerPBCSynchronizer(); /* ------------------------------------------------------------------------ */ /* Explicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the stuff for the explicit scheme void initExplicit(); /// initialize the array needed by updateResidual (residual, current_position) void initializeUpdateResidualData(); /// update the current position vector void updateCurrentPosition(); /// assemble the residual for the explicit scheme void updateResidual(bool need_initialize = true); /** * \brief compute the acceleration from the residual * this function is the explicit equivalent to solveDynamic in implicit * In the case of lumped mass just divide the residual by the mass * In the case of not lumped mass call solveDynamic<_acceleration_corrector> */ void updateAcceleration(); /// Solve the system @f[ A x = \alpha b @f] with A a lumped matrix void solveLumped(Vector<Real> & x, const Vector<Real> & A, const Vector<Real> & b, const Vector<bool> & boundary, Real alpha); /// explicit integration predictor void explicitPred(); /// explicit integration corrector void explicitCorr(); /* ------------------------------------------------------------------------ */ /* Implicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver and the jacobian_matrix (called by initImplicit) void initSolver(SolverOptions & options = _solver_no_options); /// initialize the stuff for the implicit solver void initImplicit(bool dynamic = false, SolverOptions & solver_options = _solver_no_options); /// solve Ma = f to get the initial acceleration void initialAcceleration(); /// assemble the stiffness matrix void assembleStiffnessMatrix(); /// solve @f[ A\delta u = f_ext - f_int @f] in displacement void solveDynamic(); /// solve Ku = f void solveStatic(); /// test the convergence (norm of increment) bool testConvergenceIncrement(Real tolerance); bool testConvergenceIncrement(Real tolerance, Real & error); /// test the convergence (norm of residual) bool testConvergenceResidual(Real tolerance); bool testConvergenceResidual(Real tolerance, Real & error); /// implicit time integration predictor void implicitPred(); /// implicit time integration corrector void implicitCorr(); protected: /// finish the computation of residual to solve in increment void updateResidualInternal(); /// compute A and solve @f[ A\delta u = f_ext - f_int @f] template<NewmarkBeta::IntegrationSchemeCorrectorType type> void solveDynamic(Vector<Real> & increment); /* ------------------------------------------------------------------------ */ /* Boundaries (solid_mechanics_model_boundary.cc) */ /* ------------------------------------------------------------------------ */ public: class SurfaceLoadFunctor { public: virtual void traction(__attribute__ ((unused)) const types::Vector<Real> & position, __attribute__ ((unused)) types::Vector<Real> & traction, __attribute__ ((unused)) const types::Vector<Real> & normal, __attribute__ ((unused)) Surface surface_id) { AKANTU_DEBUG_TO_IMPLEMENT(); } virtual void stress(__attribute__ ((unused)) const types::Vector<Real> & position, __attribute__ ((unused)) types::Matrix & stress, __attribute__ ((unused)) const types::Vector<Real> & normal, __attribute__ ((unused)) Surface surface_id) { AKANTU_DEBUG_TO_IMPLEMENT(); } }; /// compute force vector from a function(x,y,z) that describe stresses void computeForcesFromFunction(BoundaryFunction in_function, BoundaryFunctionType function_type) __attribute__((deprecated)); template<class Functor> void computeForcesFromFunction(Functor & functor, BoundaryFunctionType function_type); /// integrate a force on the boundary by providing a stress tensor void computeForcesByStressTensor(const Vector<Real> & stresses, const ElementType & type, const GhostType & ghost_type); /// integrate a force on the boundary by providing a traction vector void computeForcesByTractionVector(const Vector<Real> & tractions, const ElementType & type, const GhostType & ghost_type); /// synchronize the ghost element boundaries values void synchronizeBoundaries(); /* ------------------------------------------------------------------------ */ /* Materials (solid_mechanics_model_material.cc) */ /* ------------------------------------------------------------------------ */ public: /// register a material in the dynamic database Material & registerNewMaterial(const ID & mat_type, const std::string & opt_param = ""); template <typename M> Material & registerNewCustomMaterial(const ID & mat_type, const std::string & opt_param = ""); /// read the material files to instantiate all the materials void readMaterials(const std::string & filename); /// read a custom material with a keyword and class as template template <typename M> UInt readCustomMaterial(const std::string & filename, const std::string & keyword); /// Use a UIntData in the mesh to specify the material to use per element void setMaterialIDsFromIntData(const std::string & data_name); protected: // /// read properties part of a material file and create the material // template <typename M> // Material * readMaterialProperties(std::ifstream & infile, // ID mat_id, // UInt ¤t_line); /* ------------------------------------------------------------------------ */ /* Mass (solid_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix void assembleMass(); protected: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); void assembleMass(GhostType ghost_type); /// fill a vector of rho void computeRho(Vector<Real> & rho, ElementType type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: - inline virtual UInt getNbDataToPack(const Element & element, - SynchronizationTag tag) const; - - inline virtual UInt getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const; + inline virtual UInt getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const; - inline virtual void packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const; + inline virtual void packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const; - inline virtual void unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag); + inline virtual void unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag); inline virtual UInt getNbDataToPack(SynchronizationTag tag) const; - inline virtual UInt getNbDataToUnpack(SynchronizationTag tag) const; inline virtual void packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const; inline virtual void unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag); +protected: + inline void splitElementByMaterial(const Vector<Element> & elements, + Vector<Element> * elements_per_mat) const; + + + template<typename T> + inline void packElementDataHelper(Vector<T> & data_to_pack, + CommunicationBuffer & buffer, + const Vector<Element> & element) const; + + /* -------------------------------------------------------------------------- */ + template<typename T> + inline void unpackElementDataHelper(Vector<T> & data_to_unpack, + CommunicationBuffer & buffer, + const Vector<Element> & element) const; + + /* -------------------------------------------------------------------------- */ + template<typename T, bool pack_helper> + inline void packUnpackElementDataHelper(Vector<T> & data, + CommunicationBuffer & buffer, + const Vector<Element> & element) const; /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: virtual void onNodesAdded (const Vector<UInt> & nodes_list); + virtual void onNodesRemoved(const Vector<UInt> & element_list, + const Vector<UInt> & new_numbering); virtual void onElementsAdded (const Vector<Element> & nodes_list); + virtual void onElementsRemoved(const Vector<Element> & element_list, + const ByElementTypeUInt & new_numbering); + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the current value of the time step AKANTU_GET_MACRO(TimeStep, time_step, Real); /// set the value of the time step AKANTU_SET_MACRO(TimeStep, time_step, Real); /// 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, Vector<Real> &); /// get the SolidMechanicsModel::current_position vector \warn only consistent /// after a call to SolidMechanicsModel::updateCurrentPosition AKANTU_GET_MACRO(CurrentPosition, *current_position, const Vector<Real> &); /// get the SolidMechanicsModel::increment vector \warn only consistent if /// SolidMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *increment, Vector<Real> &); /// get the lumped SolidMechanicsModel::mass vector AKANTU_GET_MACRO(Mass, *mass, Vector<Real> &); /// get the SolidMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Vector<Real> &); /// get the SolidMechanicsModel::acceleration vector, updated by /// SolidMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Vector<Real> &); /// get the SolidMechanicsModel::force vector (boundary forces) AKANTU_GET_MACRO(Force, *force, Vector<Real> &); /// get the SolidMechanicsModel::residual vector, computed by /// SolidMechanicsModel::updateResidual AKANTU_GET_MACRO(Residual, *residual, Vector<Real> &); /// get the SolidMechanicsModel::boundary vector AKANTU_GET_MACRO(Boundary, *boundary, Vector<bool> &); /// get the SolidMechnicsModel::incrementAcceleration vector AKANTU_GET_MACRO(IncrementAcceleration, *increment_acceleration, Vector<Real> &); /// get the value of the SolidMechanicsModel::increment_flag AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool); /// get the SolidMechanicsModel::element_material vector corresponding to a /// given akantu::ElementType AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementMaterial, element_material, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementMaterial, element_material, UInt); /// vectors containing local material element index for each global element index AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementIndexByMaterial, element_index_by_material, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementIndexByMaterial, element_index_by_material, UInt); /// get a particular material inline Material & getMaterial(UInt mat_index); inline const Material & getMaterial(UInt mat_index) const; /// give the number of materials inline UInt getNbMaterials() const { return materials.size(); }; /// give the material internal index from its id Int getInternalIndexFromID(const ID & id) const; /// compute the stable time step Real getStableTimeStep(); /// compute the potential energy Real getPotentialEnergy(); /// compute the kinetic energy Real getKineticEnergy(); /// compute the external work (for impose displacement, the velocity should be given too) Real getExternalWork(); /// get the energies Real getEnergy(std::string id); /// set the Contact object AKANTU_SET_MACRO(Contact, contact, Contact *); /** * @brief set the SolidMechanicsModel::increment_flag to on, the activate the * update of the SolidMechanicsModel::increment vector */ void setIncrementFlagOn(); /// get the stiffness matrix AKANTU_GET_MACRO(StiffnessMatrix, *stiffness_matrix, SparseMatrix &); /// get the mass matrix AKANTU_GET_MACRO(MassMatrix, *mass_matrix, SparseMatrix &); inline FEM & getFEMBoundary(std::string name = ""); /// get integrator AKANTU_GET_MACRO(Integrator, *integrator, const IntegrationScheme2ndOrder &); /// get access to the internal solver AKANTU_GET_MACRO(Solver, *solver, Solver &); protected: /// compute the stable time step Real getStableTimeStep(const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Vector<Real> * displacement; /// lumped mass array Vector<Real> * mass; /// velocities array Vector<Real> * velocity; /// accelerations array Vector<Real> * acceleration; /// accelerations array Vector<Real> * increment_acceleration; /// forces array Vector<Real> * force; /// residuals array Vector<Real> * residual; /// boundaries array Vector<bool> * boundary; /// array of current position used during update residual Vector<Real> * current_position; /// mass matrix SparseMatrix * mass_matrix; /// velocity damping matrix SparseMatrix * velocity_damping_matrix; /// stiffness matrix SparseMatrix * stiffness_matrix; /// jacobian matrix @f[A = cM + dD + K@f] with @f[c = \frac{1}{\beta \Delta t^2}, d = \frac{\gamma}{\beta \Delta t} @f] SparseMatrix * jacobian_matrix; /// materials of all elements ByElementTypeUInt element_material; /// vectors containing local material element index for each global element index ByElementTypeUInt element_index_by_material; /// list of used materials std::vector<Material *> materials; /// integration scheme of second order used IntegrationScheme2ndOrder * integrator; /// increment of displacement Vector<Real> * increment; /// flag defining if the increment must be computed or not bool increment_flag; /// solver for implicit Solver * solver; /// object to resolve the contact Contact * contact; /// the spatial dimension UInt spatial_dimension; /// Mesh Mesh & mesh; AnalysisMethod method; }; __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "material.hh" __BEGIN_AKANTU__ #include "solid_mechanics_model_tmpl.hh" #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "solid_mechanics_model_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const SolidMechanicsModel & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc index 5714ed8d0..0227f2d71 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc @@ -1,448 +1,526 @@ /** * @file solid_mechanics_model_inline_impl.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Jul 29 12:07:04 2010 * * @brief Implementation of the inline functions of the SolidMechanicsModel class * * @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/>. * */ /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(UInt mat_index) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(UInt mat_index) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline FEM & SolidMechanicsModel::getFEMBoundary(std::string name) { return dynamic_cast<FEM &>(getFEMClassBoundary<MyFEMType>(name)); } /* -------------------------------------------------------------------------- */ -inline UInt SolidMechanicsModel::getNbDataToPack(const Element & element, - SynchronizationTag tag) const { - AKANTU_DEBUG_IN(); +inline void SolidMechanicsModel::splitElementByMaterial(const Vector<Element> & elements, + Vector<Element> * elements_per_mat) const { + ElementType current_element_type = _not_defined; + GhostType current_ghost_type = _casper; + UInt * elem_mat = NULL; + + Vector<Element>::const_iterator<Element> it = elements.begin(); + Vector<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; + elem_mat = element_material(el.type, el.ghost_type).storage(); + } + elements_per_mat[elem_mat[el.element]].push_back(el); + } +} - UInt size = 0; - UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); +/* -------------------------------------------------------------------------- */ +template<typename T> +inline void SolidMechanicsModel::packElementDataHelper(Vector<T> & data_to_pack, + CommunicationBuffer & buffer, + const Vector<Element> & element) const { + packUnpackElementDataHelper<T, true>(data_to_pack, buffer, element); +} -#ifndef AKANTU_NDEBUG - size += spatial_dimension * sizeof(Real); /// position of the barycenter of the element (only for check) -#endif +/* -------------------------------------------------------------------------- */ +template<typename T> +inline void SolidMechanicsModel::unpackElementDataHelper(Vector<T> & data_to_unpack, + CommunicationBuffer & buffer, + const Vector<Element> & element) const { + packUnpackElementDataHelper<T, false>(data_to_unpack, buffer, element); +} - switch(tag) { - case _gst_smm_mass: { - size += nb_nodes_per_element * sizeof(Real) * spatial_dimension; // mass vector - break; - } - case _gst_smm_for_strain: { - size += nb_nodes_per_element * spatial_dimension * sizeof(Real); // displacement +/* -------------------------------------------------------------------------- */ +template<typename T, bool pack_helper> +inline void SolidMechanicsModel::packUnpackElementDataHelper(Vector<T> & data, + CommunicationBuffer & buffer, + const Vector<Element> & elements) const { + UInt nb_component = data.getNbComponent(); + UInt nb_nodes_per_element = 0; + + ElementType current_element_type = _not_defined; + GhostType current_ghost_type = _casper; + UInt * conn = NULL; + + Vector<Element>::const_iterator<Element> it = elements.begin(); + Vector<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; + conn = mesh.getConnectivity(el.type, el.ghost_type).storage(); + nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type); + } - UInt mat = element_material(element.type, _not_ghost)(element.element); - // Element mat_element = element; - // mat_element.element = element_index_by_material(element.type, _not_ghost)(element.element); - size += materials[mat]->getNbDataToPack(element, tag); - break; - } - case _gst_smm_boundary: { - // force, displacement, boundary - size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); - break; - } - default: { - UInt mat = element_material(element.type, _not_ghost)(element.element); - // Element mat_element = element; - // mat_element.element = element_index_by_material(element.type, _not_ghost)(element.element); - size += materials[mat]->getNbDataToPack(element, tag); - } - } + UInt el_offset = el.element * nb_nodes_per_element; + for (UInt n = 0; n < nb_nodes_per_element; ++n) { + UInt offset_conn = conn[el_offset + n]; + types::Vector<T> data_vect(data.storage() + offset_conn * nb_component, + nb_component); - AKANTU_DEBUG_OUT(); - return size; + if(pack_helper) + buffer << data_vect; + else + buffer >> data_vect; + } + } } /* -------------------------------------------------------------------------- */ -inline UInt SolidMechanicsModel::getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const { +inline UInt SolidMechanicsModel::getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; - UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); #ifndef AKANTU_NDEBUG - size += spatial_dimension * sizeof(Real); /// position of the barycenter of the element (only for check) + size += elements.getSize() * spatial_dimension * sizeof(Real); /// position of the barycenter of the element (only for check) #endif + UInt nb_nodes_per_element = 0; + + Vector<Element>::const_iterator<Element> it = elements.begin(); + Vector<Element>::const_iterator<Element> end = elements.end(); + for (; it != end; ++it) { + const Element & el = *it; + nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); + } + switch(tag) { case _gst_smm_mass: { size += nb_nodes_per_element * sizeof(Real) * spatial_dimension; // mass vector break; } case _gst_smm_for_strain: { size += nb_nodes_per_element * spatial_dimension * sizeof(Real); // displacement - UInt mat = element_material(element.type, _ghost)(element.element); - // Element mat_element = element; - // mat_element.element = element_index_by_material(element.type, _not_ghost)(element.element); - size += materials[mat]->getNbDataToUnpack(element, tag); - break; + //UInt mat = element_material(element.type, _not_ghost)(element.element); + //size += materials[mat]->getNbDataToPack(element, tag); + break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } - default: { - UInt mat = element_material(element.type, _ghost)(element.element); - // Element mat_element = element; - // mat_element.element = element_index_by_material(element.type, _not_ghost)(element.element); - size += materials[mat]->getNbDataToUnpack(element, tag); + default: { } } + + + Vector<Element> * elements_per_mat = new Vector<Element>[materials.size()]; + this->splitElementByMaterial(elements, elements_per_mat); + + for (UInt i = 0; i < materials.size(); ++i) { + size += materials[i]->getNbDataForElements(elements_per_mat[i], tag); } + delete [] elements_per_mat; AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ -inline void SolidMechanicsModel::packData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) const { +inline void SolidMechanicsModel::packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) const { AKANTU_DEBUG_IN(); - GhostType ghost_type = _not_ghost; + // GhostType ghost_type = _not_ghost; - UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); - UInt el_offset = element.element * nb_nodes_per_element; - UInt * conn = mesh.getConnectivity(element.type, ghost_type).storage(); + // UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); + // UInt el_offset = element.element * nb_nodes_per_element; + // UInt * conn = mesh.getConnectivity(element.type, ghost_type).storage(); #ifndef AKANTU_NDEBUG - types::RVector barycenter(spatial_dimension); - mesh.getBarycenter(element.element, element.type, barycenter.storage(), ghost_type); - buffer << barycenter; + Vector<Element>::const_iterator<Element> bit = elements.begin(); + Vector<Element>::const_iterator<Element> bend = elements.end(); + for (; bit != bend; ++bit) { + const Element & element = *bit; + types::RVector barycenter(spatial_dimension); + mesh.getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); + buffer << barycenter; + } #endif switch(tag) { case _gst_smm_mass: { - for (UInt n = 0; n < nb_nodes_per_element; ++n) { - UInt offset_conn = conn[el_offset + n]; - Vector<Real>::iterator<types::RVector> it_mass = mass->begin(spatial_dimension); - buffer << it_mass[offset_conn]; - } + packElementDataHelper(*mass, buffer, elements); + // for (UInt n = 0; n < nb_nodes_per_element; ++n) { + // UInt offset_conn = conn[el_offset + n]; + // Vector<Real>::iterator<types::RVector> it_mass = mass->begin(spatial_dimension); + // buffer << it_mass[offset_conn]; + // } break; } case _gst_smm_for_strain: { - Vector<Real>::iterator<types::RVector> it_disp = displacement->begin(spatial_dimension); - for (UInt n = 0; n < nb_nodes_per_element; ++n) { - UInt offset_conn = conn[el_offset + n]; - buffer << it_disp[offset_conn]; - } - - UInt mat = element_material(element.type, ghost_type)(element.element); - Element mat_element = element; - mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); - materials[mat]->packData(buffer, mat_element, tag); + packElementDataHelper(*displacement, buffer, elements); + // Vector<Real>::iterator<types::RVector> it_disp = displacement->begin(spatial_dimension); + // for (UInt n = 0; n < nb_nodes_per_element; ++n) { + // UInt offset_conn = conn[el_offset + n]; + // buffer << it_disp[offset_conn]; + // } + + // UInt mat = element_material(element.type, ghost_type)(element.element); + // Element mat_element = element; + // mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); + // materials[mat]->packData(buffer, mat_element, tag); break; } case _gst_smm_boundary: { - Vector<Real>::iterator<types::RVector> it_force = force->begin(spatial_dimension); - Vector<Real>::iterator<types::RVector> it_velocity = velocity->begin(spatial_dimension); - Vector<bool>::iterator<types::Vector<bool> > it_boundary = boundary->begin(spatial_dimension); - - for (UInt n = 0; n < nb_nodes_per_element; ++n) { - UInt offset_conn = conn[el_offset + n]; - - buffer << it_force [offset_conn]; - buffer << it_velocity[offset_conn]; - buffer << it_boundary[offset_conn]; - } + packElementDataHelper(*force, buffer, elements); + packElementDataHelper(*velocity, buffer, elements); + packElementDataHelper(*boundary, buffer, elements); + // Vector<Real>::iterator<types::RVector> it_force = force->begin(spatial_dimension); + // Vector<Real>::iterator<types::RVector> it_velocity = velocity->begin(spatial_dimension); + // Vector<bool>::iterator<types::Vector<bool> > it_boundary = boundary->begin(spatial_dimension); + + // for (UInt n = 0; n < nb_nodes_per_element; ++n) { + // UInt offset_conn = conn[el_offset + n]; + + // buffer << it_force [offset_conn]; + // buffer << it_velocity[offset_conn]; + // buffer << it_boundary[offset_conn]; + // } break; } default: { - UInt mat = element_material(element.type, ghost_type)(element.element); - Element mat_element = element; - mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); - materials[mat]->packData(buffer, mat_element, tag); + // UInt mat = element_material(element.type, ghost_type)(element.element); + // Element mat_element = element; + // mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); + // materials[mat]->packData(buffer, mat_element, tag); //AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } + Vector<Element> * elements_per_mat = new Vector<Element>[materials.size()]; + splitElementByMaterial(elements, elements_per_mat); + + for (UInt i = 0; i < materials.size(); ++i) { + materials[i]->packElementData(buffer, elements_per_mat[i], tag); + } + + delete [] elements_per_mat; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag) { +inline void SolidMechanicsModel::unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag) { AKANTU_DEBUG_IN(); - GhostType ghost_type = _ghost; + // GhostType ghost_type = _ghost; - UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); - UInt el_offset = element.element * nb_nodes_per_element; - UInt * conn = mesh.getConnectivity(element.type, ghost_type).values; + // UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); + // UInt el_offset = element.element * nb_nodes_per_element; + // UInt * conn = mesh.getConnectivity(element.type, ghost_type).values; #ifndef AKANTU_NDEBUG - types::RVector barycenter_loc(spatial_dimension); - mesh.getBarycenter(element.element, element.type, barycenter_loc.storage(), ghost_type); - - types::RVector barycenter(spatial_dimension); - buffer >> barycenter; - Real tolerance = 1e-15; - for (UInt i = 0; i < spatial_dimension; ++i) { - if(!(std::abs(barycenter(i) - barycenter_loc(i)) <= tolerance)) - AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: " - << element - << "(barycenter[" << i << "] = " << barycenter_loc(i) - << " and buffer[" << i << "] = " << barycenter(i) << ") - tag: " << tag); + Vector<Element>::const_iterator<Element> bit = elements.begin(); + Vector<Element>::const_iterator<Element> bend = elements.end(); + for (; bit != bend; ++bit) { + const Element & element = *bit; + + types::RVector barycenter_loc(spatial_dimension); + mesh.getBarycenter(element.element, element.type, barycenter_loc.storage(), element.ghost_type); + + types::RVector barycenter(spatial_dimension); + buffer >> barycenter; + Real tolerance = 1e-15; + for (UInt i = 0; i < spatial_dimension; ++i) { + if(!(std::abs(barycenter(i) - barycenter_loc(i)) <= tolerance)) + AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: " + << element + << "(barycenter[" << i << "] = " << barycenter_loc(i) + << " and buffer[" << i << "] = " << barycenter(i) << ") - tag: " << tag); + } } #endif switch(tag) { case _gst_smm_mass: { - for (UInt n = 0; n < nb_nodes_per_element; ++n) { - UInt offset_conn = conn[el_offset + n]; - Vector<Real>::iterator<types::RVector> it_mass = mass->begin(spatial_dimension); - buffer >> it_mass[offset_conn]; - } + unpackElementDataHelper(*mass, buffer, elements); + // for (UInt n = 0; n < nb_nodes_per_element; ++n) { + // UInt offset_conn = conn[el_offset + n]; + // Vector<Real>::iterator<types::RVector> it_mass = mass->begin(spatial_dimension); + // buffer >> it_mass[offset_conn]; + // } break; } case _gst_smm_for_strain: { - Vector<Real>::iterator<types::RVector> it_disp = displacement->begin(spatial_dimension); - for (UInt n = 0; n < nb_nodes_per_element; ++n) { - UInt offset_conn = conn[el_offset + n]; - buffer >> it_disp[offset_conn]; - } - - UInt mat = element_material(element.type, ghost_type)(element.element); - Element mat_element = element; - mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); - materials[mat]->unpackData(buffer, mat_element, tag); + unpackElementDataHelper(*displacement, buffer, elements); + // Vector<Real>::iterator<types::RVector> it_disp = displacement->begin(spatial_dimension); + // for (UInt n = 0; n < nb_nodes_per_element; ++n) { + // UInt offset_conn = conn[el_offset + n]; + // buffer >> it_disp[offset_conn]; + // } + + // UInt mat = element_material(element.type, ghost_type)(element.element); + // Element mat_element = element; + // mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); + // materials[mat]->unpackData(buffer, mat_element, tag); break; } case _gst_smm_boundary: { - Vector<Real>::iterator<types::RVector> it_force = force->begin(spatial_dimension); - Vector<Real>::iterator<types::RVector> it_velocity = velocity->begin(spatial_dimension); - Vector<bool>::iterator<types::Vector<bool> > it_boundary = boundary->begin(spatial_dimension); - - for (UInt n = 0; n < nb_nodes_per_element; ++n) { - UInt offset_conn = conn[el_offset + n]; - - buffer >> it_force [offset_conn]; - buffer >> it_velocity[offset_conn]; - buffer >> it_boundary[offset_conn]; - } + unpackElementDataHelper(*force, buffer, elements); + unpackElementDataHelper(*velocity, buffer, elements); + unpackElementDataHelper(*boundary, buffer, elements); + // Vector<Real>::iterator<types::RVector> it_force = force->begin(spatial_dimension); + // Vector<Real>::iterator<types::RVector> it_velocity = velocity->begin(spatial_dimension); + // Vector<bool>::iterator<types::Vector<bool> > it_boundary = boundary->begin(spatial_dimension); + + // for (UInt n = 0; n < nb_nodes_per_element; ++n) { + // UInt offset_conn = conn[el_offset + n]; + + // buffer >> it_force [offset_conn]; + // buffer >> it_velocity[offset_conn]; + // buffer >> it_boundary[offset_conn]; + // } break; } default: { - UInt mat = element_material(element.type, ghost_type)(element.element); - Element mat_element = element; - mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); - materials[mat]->unpackData(buffer, mat_element, tag); + // UInt mat = element_material(element.type, ghost_type)(element.element); + // Element mat_element = element; + // mat_element.element = element_index_by_material(element.type, ghost_type)(element.element); + // materials[mat]->unpackData(buffer, mat_element, tag); //AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } + Vector<Element> * elements_per_mat = new Vector<Element>[materials.size()]; + splitElementByMaterial(elements, elements_per_mat); + + for (UInt i = 0; i < materials.size(); ++i) { + materials[i]->unpackElementData(buffer, elements_per_mat[i], tag); + } + + delete [] elements_per_mat; + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToPack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } - + AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToUnpack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Vector<Real>::iterator<types::RVector> it_disp = displacement->begin(spatial_dimension); Vector<Real>::iterator<types::RVector> it_velo = velocity->begin(spatial_dimension); buffer << it_disp[index]; buffer << it_velo[index]; break; } case _gst_smm_res: { Vector<Real>::iterator<types::RVector> it_res = residual->begin(spatial_dimension); buffer << it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("pack mass of node " << index << " which is " << (*mass)(index,0)); Vector<Real>::iterator<types::RVector> it_mass = mass->begin(spatial_dimension); buffer << it_mass[index]; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Vector<Real>::iterator<types::RVector> it_disp = displacement->begin(spatial_dimension); Vector<Real>::iterator<types::RVector> it_velo = velocity->begin(spatial_dimension); buffer >> it_disp[index]; buffer >> it_velo[index]; break; } case _gst_smm_res: { Vector<Real>::iterator<types::RVector> it_res = residual->begin(spatial_dimension); buffer >> it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("mass of node " << index << " was " << (*mass)(index,0)); Vector<Real>::iterator<types::RVector> it_mass = mass->begin(spatial_dimension); buffer >> it_mass[index]; AKANTU_DEBUG_INFO("mass of node " << index << " is now " << (*mass)(index,0)); break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ #include "sparse_matrix.hh" #include "solver.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<NewmarkBeta::IntegrationSchemeCorrectorType type> void SolidMechanicsModel::solveDynamic(Vector<Real> & increment) { AKANTU_DEBUG_INFO("Solving Ma + Cv + Ku = f"); NewmarkBeta * nmb_int = dynamic_cast<NewmarkBeta *>(integrator); Real c = nmb_int->getAccelerationCoefficient<type>(time_step); Real d = nmb_int->getVelocityCoefficient<type>(time_step); Real e = nmb_int->getDisplacementCoefficient<type>(time_step); // A = c M + d C + e K jacobian_matrix->clear(); if(type != NewmarkBeta::_acceleration_corrector) jacobian_matrix->add(*stiffness_matrix, e); jacobian_matrix->add(*mass_matrix, c); mass_matrix->saveMatrix("M.mtx"); if(velocity_damping_matrix) jacobian_matrix->add(*velocity_damping_matrix, d); jacobian_matrix->applyBoundary(*boundary); #ifndef AKANTU_NDEBUG if(AKANTU_DEBUG_TEST(dblDump)) jacobian_matrix->saveMatrix("J.mtx"); #endif jacobian_matrix->saveMatrix("J.mtx"); solver->setRHS(*residual); // solve A w = f solver->solve(increment); } /* -------------------------------------------------------------------------- */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_mass.cc b/src/model/solid_mechanics/solid_mechanics_model_mass.cc index d2bedaaf6..e8cfa277b 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_mass.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_mass.cc @@ -1,154 +1,154 @@ /** * @file solid_mechanics_model_mass.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Mon Oct 4 15:21:23 2010 * * @brief function handling mass computation * * @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 "solid_mechanics_model.hh" #include "material.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMassLumped() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); mass->clear(); assembleMassLumped(_not_ghost); assembleMassLumped(_ghost); /// for not connected nodes put mass to one in order to avoid /// wrong range in paraview Real * mass_values = mass->values; for (UInt i = 0; i < nb_nodes; ++i) { if (fabs(mass_values[i]) < std::numeric_limits<Real>::epsilon() || Math::isnan(mass_values[i])) mass_values[i] = 1.; } synch_registry->synchronize(_gst_smm_mass); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMassLumped(GhostType ghost_type) { AKANTU_DEBUG_IN(); FEM & fem = getFEM(); Vector<Real> rho_1(0,1); 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; computeRho(rho_1, type, ghost_type); AKANTU_DEBUG_ASSERT(dof_synchronizer, "DOFSynchronizer number must not be initialized"); fem.assembleFieldLumped(rho_1, spatial_dimension,*mass, dof_synchronizer->getLocalDOFEquationNumbers(), type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMass() { AKANTU_DEBUG_IN(); // if(!dof_synchronizer) dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); // UInt nb_global_node = mesh.getNbGlobalNodes(); std::stringstream sstr; sstr << id << ":mass_matrix"; // mass_matrix = new SparseMatrix(nb_global_node * spatial_dimension, _symmetric, // spatial_dimension, sstr.str(), memory_id); // mass_matrix->buildProfile(mesh, *dof_synchronizer); mass_matrix = new SparseMatrix(*jacobian_matrix, sstr.str(), memory_id); assembleMass(_not_ghost); // assembleMass(_ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMass(GhostType ghost_type) { AKANTU_DEBUG_IN(); MyFEMType & fem = getFEMClass<MyFEMType>(); Vector<Real> rho_1(0,1); //UInt nb_element; mass_matrix->clear(); 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; computeRho(rho_1, type, ghost_type); fem.assembleFieldMatrix(rho_1, spatial_dimension, *mass_matrix, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeRho(Vector<Real> & rho, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Material ** mat_val = &(materials.at(0)); FEM & fem = getFEM(); UInt nb_element = fem.getMesh().getNbElement(type,ghost_type); - UInt * elem_mat_val = element_material(type, ghost_type).storage(); + Vector<UInt> & elem_mat_val = element_material(type, ghost_type); UInt nb_quadrature_points = fem.getNbQuadraturePoints(type, ghost_type); rho.resize(nb_element * nb_quadrature_points); Real * rho_1_val = rho.values; /// compute @f$ rho @f$ for each nodes of each element for (UInt el = 0; el < nb_element; ++el) { - Real mat_rho = mat_val[elem_mat_val[el]]->getParam<Real>("rho"); /// here rho is constant in an element + Real mat_rho = mat_val[elem_mat_val(el)]->getParam<Real>("rho"); /// here rho is constant in an element for (UInt n = 0; n < nb_quadrature_points; ++n) { *rho_1_val++ = mat_rho; } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/solver/sparse_matrix.cc b/src/solver/sparse_matrix.cc index 7de9a4929..6a42505f0 100644 --- a/src/solver/sparse_matrix.cc +++ b/src/solver/sparse_matrix.cc @@ -1,429 +1,429 @@ /** * @file sparse_matrix.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Tue Oct 26 18:25:07 2010 * * @brief implementation of the SparseMatrix class * * @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 <fstream> /* -------------------------------------------------------------------------- */ #include "sparse_matrix.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ SparseMatrix::SparseMatrix(UInt size, const SparseMatrixType & sparse_matrix_type, UInt nb_degree_of_freedom, const ID & id, const MemoryID & memory_id) : Memory(memory_id), id(id), sparse_matrix_type(sparse_matrix_type), nb_degree_of_freedom(nb_degree_of_freedom), size(size), nb_non_zero(0), irn(0,1,"irn"), jcn(0,1,"jcn"), a(0,1,"A") { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); nb_proc = comm.getNbProc(); dof_synchronizer = NULL; irn_save = NULL; jcn_save = NULL; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix::SparseMatrix(const SparseMatrix & matrix, const ID & id, const MemoryID & memory_id) : Memory(memory_id), id(id), sparse_matrix_type(matrix.sparse_matrix_type), nb_degree_of_freedom(matrix.nb_degree_of_freedom), size(matrix.size), nb_proc(matrix.nb_proc), nb_non_zero(matrix.nb_non_zero), irn(matrix.irn, true), jcn(matrix.jcn, true), a(matrix.getA(), true), irn_jcn_k(matrix.irn_jcn_k) { AKANTU_DEBUG_IN(); size_save = 0; irn_save = NULL; jcn_save = NULL; dof_synchronizer = matrix.dof_synchronizer; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix::~SparseMatrix() { AKANTU_DEBUG_IN(); // if (irn_jcn_to_k) delete irn_jcn_to_k; if(irn_save) delete irn_save; if(jcn_save) delete jcn_save; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrix::buildProfile(const Mesh & mesh, const DOFSynchronizer & dof_synchronizer) { AKANTU_DEBUG_IN(); // if(irn_jcn_to_k) delete irn_jcn_to_k; // irn_jcn_to_k = new std::map<std::pair<UInt, UInt>, UInt>; clearProfile(); this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer); coordinate_list_map::iterator irn_jcn_k_it; Int * eq_nb_val = dof_synchronizer.getGlobalDOFEquationNumbers().values; Mesh::type_iterator it = mesh.firstType(mesh.getSpatialDimension(), _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType (mesh.getSpatialDimension(), _not_ghost, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom; UInt * conn_val = mesh.getConnectivity(*it, _not_ghost).values; Int * local_eq_nb_val = new Int[nb_degree_of_freedom * nb_nodes_per_element]; for (UInt e = 0; e < nb_element; ++e) { Int * tmp_local_eq_nb_val = local_eq_nb_val; for (UInt i = 0; i < nb_nodes_per_element; ++i) { UInt n = conn_val[i]; for (UInt d = 0; d < nb_degree_of_freedom; ++d) { *tmp_local_eq_nb_val++ = eq_nb_val[n * nb_degree_of_freedom + d]; } // memcpy(tmp_local_eq_nb_val, eq_nb_val + n * nb_degree_of_freedom, nb_degree_of_freedom * sizeof(Int)); // tmp_local_eq_nb_val += nb_degree_of_freedom; } for (UInt i = 0; i < size_mat; ++i) { UInt c_irn = local_eq_nb_val[i]; if(c_irn < size) { UInt j_start = (sparse_matrix_type == _symmetric) ? i : 0; for (UInt j = j_start; j < size_mat; ++j) { UInt c_jcn = local_eq_nb_val[j]; if(c_jcn < size) { KeyCOO irn_jcn = key(c_irn, c_jcn); irn_jcn_k_it = irn_jcn_k.find(irn_jcn); if (irn_jcn_k_it == irn_jcn_k.end()) { irn_jcn_k[irn_jcn] = nb_non_zero; irn.push_back(c_irn + 1); jcn.push_back(c_jcn + 1); nb_non_zero++; } } } } } conn_val += nb_nodes_per_element; } delete [] local_eq_nb_val; } for (UInt i = 0; i < size; ++i) { KeyCOO irn_jcn = key(i, i); irn_jcn_k_it = irn_jcn_k.find(irn_jcn); if(irn_jcn_k_it == irn_jcn_k.end()) { irn_jcn_k[irn_jcn] = nb_non_zero; irn.push_back(i + 1); jcn.push_back(i + 1); nb_non_zero++; } } a.resize(nb_non_zero); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrix::applyBoundary(const Vector<bool> & boundary) { AKANTU_DEBUG_IN(); const DOFSynchronizer::GlobalEquationNumberMap & local_eq_num_to_global = dof_synchronizer->getGlobalEquationNumberToLocal(); Int * irn_val = irn.values; Int * jcn_val = jcn.values; Real * a_val = a.values; for (UInt i = 0; i < nb_non_zero; ++i) { UInt ni = local_eq_num_to_global.find(*irn_val - 1)->second; UInt nj = local_eq_num_to_global.find(*jcn_val - 1)->second; if(boundary.values[ni] || boundary.values[nj]) { if (*irn_val != *jcn_val) *a_val = 0; else { if(dof_synchronizer->getDOFTypes()(ni) >= 0) *a_val = 0; else *a_val = 1; } } irn_val++; jcn_val++; a_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrix::removeBoundary(const Vector<bool> & boundary) { AKANTU_DEBUG_IN(); if(irn_save) delete irn_save; if(jcn_save) delete jcn_save; irn_save = new Vector<Int>(irn, true); jcn_save = new Vector<Int>(jcn, true); UInt n = boundary.getSize()*boundary.getNbComponent(); UInt * perm = new UInt[n]; size_save = size; size = 0; for (UInt i = 0; i < n; ++i) { if(!boundary.values[i]) { perm[i] = size; // std::cout << "perm["<< i <<"] = " << size << std::endl; size++; } } for (UInt i = 0; i < nb_non_zero;) { - if(boundary.values[irn.at(i) - 1] || boundary.values[jcn.at(i) - 1]) { + if(boundary.values[irn(i) - 1] || boundary.values[jcn(i) - 1]) { irn.erase(i); jcn.erase(i); a.erase(i); nb_non_zero--; } else { - irn.values[i] = perm[irn.values[i] - 1] + 1; - jcn.values[i] = perm[jcn.values[i] - 1] + 1; + irn(i) = perm[irn(i) - 1] + 1; + jcn(i) = perm[jcn(i) - 1] + 1; i++; } } delete [] perm; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrix::restoreProfile() { AKANTU_DEBUG_IN(); irn.resize(irn_save->getSize()); jcn.resize(jcn_save->getSize()); nb_non_zero = irn.getSize(); a.resize(nb_non_zero); size = size_save; memcpy(irn.values, irn_save->values, irn.getSize()*sizeof(Int)); memcpy(jcn.values, jcn_save->values, jcn.getSize()*sizeof(Int)); delete irn_save; irn_save = NULL; delete jcn_save; jcn_save = NULL; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrix::saveProfile(const std::string & filename) const { AKANTU_DEBUG_IN(); std::ofstream outfile; outfile.open(filename.c_str()); outfile << "%%MatrixMarket matrix coordinate pattern"; if(sparse_matrix_type == _symmetric) outfile << " symmetric"; else outfile << " general"; outfile << std::endl; UInt m = size; outfile << m << " " << m << " " << nb_non_zero << std::endl; for (UInt i = 0; i < nb_non_zero; ++i) { outfile << irn.values[i] << " " << jcn.values[i] << " 1" << std::endl; } outfile.close(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrix::saveMatrix(const std::string & filename) const { AKANTU_DEBUG_IN(); std::ofstream outfile; outfile.precision(std::numeric_limits<Real>::digits10); outfile.open(filename.c_str()); outfile << "%%MatrixMarket matrix coordinate real"; if(sparse_matrix_type == _symmetric) outfile << " symmetric"; else outfile << " general"; outfile << std::endl; outfile << size << " " << size << " " << nb_non_zero << std::endl; for (UInt i = 0; i < nb_non_zero; ++i) { outfile << irn(i) << " " << jcn(i) << " " << a(i) << std::endl; } outfile.close(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Vector<Real> & operator*=(Vector<Real> & vect, const SparseMatrix & mat) { AKANTU_DEBUG_IN(); // AKANTU_DEBUG_ASSERT((vect.getSize()*vect.getNbComponent() == mat.getSize()) && // (vect.getNbComponent() == mat.getNbDegreOfFreedom()), // "The size of the matrix and the vector do not match"); const SparseMatrixType & sparse_matrix_type = mat.getSparseMatrixType(); DOFSynchronizer * dof_synchronizer = mat.getDOFSynchronizerPointer(); UInt nb_non_zero = mat.getNbNonZero(); Real * tmp = new Real [vect.getNbComponent() * vect.getSize()]; std::fill_n(tmp, vect.getNbComponent() * vect.getSize(), 0); Int * i_val = mat.getIRN().values; Int * j_val = mat.getJCN().values; Real * a_val = mat.getA().values; Real * vect_val = vect.values; for (UInt k = 0; k < nb_non_zero; ++k) { UInt i = *(i_val++); UInt j = *(j_val++); Real a = *(a_val++); UInt local_i = i - 1; UInt local_j = j - 1; if(dof_synchronizer) { local_i = dof_synchronizer->getDOFLocalID(local_i); local_j = dof_synchronizer->getDOFLocalID(local_j); } tmp[local_i] += a * vect_val[local_j]; if(sparse_matrix_type == _symmetric && (local_i != local_j)) tmp[local_j] += a * vect_val[local_i]; } memcpy(vect_val, tmp, vect.getNbComponent() * vect.getSize() * sizeof(Real)); delete [] tmp; if(dof_synchronizer) dof_synchronizer->reduceSynchronize<AddOperation<Real> >(vect); AKANTU_DEBUG_OUT(); return vect; } /* -------------------------------------------------------------------------- */ void SparseMatrix::copyContent(const SparseMatrix & matrix) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(nb_non_zero == matrix.getNbNonZero(), "The to matrix don't have the same profiles"); memcpy(a.values, matrix.getA().values, nb_non_zero * sizeof(Real)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseMatrix::add(const SparseMatrix & matrix, Real alpha) { AKANTU_DEBUG_ASSERT(nb_non_zero == matrix.getNbNonZero(), "The to matrix don't have the same profiles"); Real * a_val = a.values; Real * b_val = matrix.a.values; for (UInt n = 0; n < nb_non_zero; ++n) { *a_val++ += alpha * *b_val++; } } /* -------------------------------------------------------------------------- */ void SparseMatrix::lump(Vector<Real> & lumped) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT((lumped.getNbComponent() == nb_degree_of_freedom), "The size of the matrix and the vector do not match"); UInt vect_size = size / nb_degree_of_freedom; if(dof_synchronizer) vect_size = dof_synchronizer->getNbDOFs() / nb_degree_of_freedom; lumped.resize(vect_size); lumped.clear(); Int * i_val = irn.values; Int * j_val = jcn.values; Real * a_val = a.values; Real * vect_val = lumped.values; for (UInt k = 0; k < nb_non_zero; ++k) { UInt i = *(i_val++); UInt j = *(j_val++); Real a = *(a_val++); UInt local_i = i - 1; UInt local_j = j - 1; if(dof_synchronizer) { local_i = dof_synchronizer->getDOFLocalID(local_i); local_j = dof_synchronizer->getDOFLocalID(local_j); } vect_val[local_i] += a; if(sparse_matrix_type == _symmetric && (i != j)) vect_val[local_j] += a; } if(dof_synchronizer) dof_synchronizer->reduceSynchronize<AddOperation<Real> >(lumped); AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/synchronizer/data_accessor.hh b/src/synchronizer/data_accessor.hh index 3381c2d00..82fdd535a 100644 --- a/src/synchronizer/data_accessor.hh +++ b/src/synchronizer/data_accessor.hh @@ -1,160 +1,151 @@ /** * @file data_accessor.hh * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @date Wed Jun 15 14:43:23 2011 * * @brief Interface of accessors for pack_unpack system * * @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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DATA_ACCESSOR_HH__ #define __AKANTU_DATA_ACCESSOR_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "communication_buffer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class DataAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DataAccessor(); virtual ~DataAccessor(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /** - * @brief get the number of data to send for a given akantu::Element and a + * @brief get the number of data to exchange for a given akantu::Element and a * given akantu::SynchronizationTag */ - virtual UInt getNbDataToPack(__attribute__((unused)) const Element & element, - __attribute__((unused)) SynchronizationTag tag) const { + virtual UInt getNbDataForElements(__attribute__((unused)) const Vector<Element> & elements, + __attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief get the number of data to send for a given * akantu::SynchronizationTag */ virtual UInt getNbDataToPack(__attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } - /** - * @brief get the number of data to receive for a given akantu::Element and a - * given akantu::SynchronizationTag - */ - virtual UInt getNbDataToUnpack(__attribute__((unused)) const Element & element, - __attribute__((unused)) SynchronizationTag tag) const { - AKANTU_DEBUG_TO_IMPLEMENT(); - } - /** * @brief get the number of data to receive for a given * akantu::SynchronizationTag */ virtual UInt getNbDataToUnpack(__attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief pack the data for a given akantu::Element and a given * akantu::SynchronizationTag */ - virtual void packData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const Element & element, - __attribute__((unused)) SynchronizationTag tag) const { + virtual void packElementData(__attribute__((unused)) CommunicationBuffer & buffer, + __attribute__((unused)) const Vector<Element> & element, + __attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief pack the data for a given index and a given * akantu::SynchronizationTag */ virtual void packData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const UInt index, __attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief unpack the data for a given akantu::Element and a given * akantu::SynchronizationTag */ - virtual void unpackData(__attribute__((unused)) CommunicationBuffer & buffer, - __attribute__((unused)) const Element & element, - __attribute__((unused)) SynchronizationTag tag) { + virtual void unpackElementData(__attribute__((unused)) CommunicationBuffer & buffer, + __attribute__((unused)) const Vector<Element> & element, + __attribute__((unused)) SynchronizationTag tag) { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief unpack the data for a given index and a given * akantu::SynchronizationTag */ virtual void unpackData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const UInt index, __attribute__((unused)) SynchronizationTag tag) { AKANTU_DEBUG_TO_IMPLEMENT(); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ // #include "data_accessor_inline_impl.cc" // /// standard output stream operator // inline std::ostream & operator <<(std::ostream & stream, const DataAccessor & _this) // { // _this.printself(stream); // return stream; // } __END_AKANTU__ #endif /* __AKANTU_DATA_ACCESSOR_HH__ */ diff --git a/src/synchronizer/distributed_synchronizer.cc b/src/synchronizer/distributed_synchronizer.cc index 0ed9375d6..c3f411c76 100644 --- a/src/synchronizer/distributed_synchronizer.cc +++ b/src/synchronizer/distributed_synchronizer.cc @@ -1,927 +1,1029 @@ /** * @file distributed_synchronizer.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Thu Aug 26 16:36:21 2010 * * @brief implementation of a communicator using a static_communicator for real * send/receive * * @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 "distributed_synchronizer.hh" #include "static_communicator.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <map> #include <iostream> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -DistributedSynchronizer::DistributedSynchronizer(SynchronizerID id, - MemoryID memory_id) : +DistributedSynchronizer::DistributedSynchronizer(Mesh & mesh, + SynchronizerID id, + MemoryID memory_id) : Synchronizer(id, memory_id), - static_communicator(&StaticCommunicator::getStaticCommunicator()) + mesh(mesh), static_communicator(&StaticCommunicator::getStaticCommunicator()) { AKANTU_DEBUG_IN(); nb_proc = static_communicator->getNbProc(); rank = static_communicator->whoAmI(); - send_element = new std::vector<Element>[nb_proc]; - recv_element = new std::vector<Element>[nb_proc]; + send_element = new Vector<Element>[nb_proc]; + recv_element = new Vector<Element>[nb_proc]; + + mesh.registerEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DistributedSynchronizer::~DistributedSynchronizer() { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { // send_buffer[p].resize(0); // recv_buffer[p].resize(0); send_element[p].clear(); recv_element[p].clear(); } // delete [] send_buffer; // delete [] recv_buffer; delete [] send_element; delete [] recv_element; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DistributedSynchronizer * DistributedSynchronizer:: createDistributedSynchronizerMesh(Mesh & mesh, const MeshPartition * partition, UInt root, SynchronizerID id, MemoryID memory_id) { AKANTU_DEBUG_IN(); const UInt TAG_SIZES = 0; const UInt TAG_CONNECTIVITY = 1; const UInt TAG_DATA = 2; const UInt TAG_PARTITIONS = 3; const UInt TAG_NB_NODES = 4; const UInt TAG_NODES = 5; const UInt TAG_COORDINATES = 6; const UInt TAG_NODES_TYPE = 7; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); - DistributedSynchronizer * communicator = new DistributedSynchronizer(id, memory_id); + DistributedSynchronizer & communicator = *(new DistributedSynchronizer(mesh, id, memory_id)); - if(nb_proc == 1) return communicator; + if(nb_proc == 1) return &communicator; UInt * local_connectivity = NULL; UInt * local_partitions = NULL; UInt * local_data = NULL; Vector<UInt> * old_nodes = mesh.getNodesGlobalIdsPointer(); Vector<Real> * nodes = mesh.getNodesPointer(); UInt spatial_dimension = nodes->getNbComponent(); /* ------------------------------------------------------------------------ */ /* Local (rank == root) */ /* ------------------------------------------------------------------------ */ if(my_rank == root) { AKANTU_DEBUG_ASSERT(partition->getNbPartition() == nb_proc, "The number of partition does not match the number of processors"); /** * connectivity and communications scheme construction */ Mesh::type_iterator it = mesh.firstType(mesh.getSpatialDimension()); Mesh::type_iterator end = mesh.lastType(mesh.getSpatialDimension()); + UInt count = 0; for(; it != end; ++it) { ElementType type = *it; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(*it); UInt nb_local_element[nb_proc]; UInt nb_ghost_element[nb_proc]; UInt nb_element_to_send[nb_proc]; memset(nb_local_element, 0, nb_proc*sizeof(UInt)); memset(nb_ghost_element, 0, nb_proc*sizeof(UInt)); memset(nb_element_to_send, 0, nb_proc*sizeof(UInt)); UInt * partition_num = partition->getPartition(type, _not_ghost).values; UInt * ghost_partition = partition->getGhostPartition(type, _ghost).values; UInt * ghost_partition_offset = partition->getGhostPartitionOffset(type, _ghost).values; UIntDataMap & uint_data_map = mesh.getUIntDataMap(type, _not_ghost); UInt nb_tags = uint_data_map.size(); /* -------------------------------------------------------------------- */ /// constructing the reordering structures for (UInt el = 0; el < nb_element; ++el) { nb_local_element[partition_num[el]]++; for (UInt part = ghost_partition_offset[el]; part < ghost_partition_offset[el + 1]; ++part) { nb_ghost_element[ghost_partition[part]]++; } nb_element_to_send[partition_num[el]] += ghost_partition_offset[el + 1] - ghost_partition_offset[el] + 1; } /// allocating buffers UInt * buffers[nb_proc]; UInt * buffers_tmp[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { UInt size = nb_nodes_per_element * (nb_local_element[p] + nb_ghost_element[p]); buffers[p] = new UInt[size]; buffers_tmp[p] = buffers[p]; } /// copying the local connectivity UInt * conn_val = mesh.getConnectivity(type, _not_ghost).values; for (UInt el = 0; el < nb_element; ++el) { memcpy(buffers_tmp[partition_num[el]], conn_val + el * nb_nodes_per_element, nb_nodes_per_element * sizeof(UInt)); buffers_tmp[partition_num[el]] += nb_nodes_per_element; } /// copying the connectivity of ghost element for (UInt el = 0; el < nb_element; ++el) { for (UInt part = ghost_partition_offset[el]; part < ghost_partition_offset[el + 1]; ++part) { UInt proc = ghost_partition[part]; memcpy(buffers_tmp[proc], conn_val + el * nb_nodes_per_element, nb_nodes_per_element * sizeof(UInt)); buffers_tmp[proc] += nb_nodes_per_element; } } UInt names_size = 0; UIntDataMap::iterator it_data; for(it_data = uint_data_map.begin(); it_data != uint_data_map.end(); ++it_data) { names_size += it_data->first.size() + 1; } /* -------->>>>-SIZE + CONNECTIVITY------------------------------------ */ /// send all connectivity and ghost information to all processors std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { UInt size[6]; size[0] = (UInt) type; size[1] = nb_local_element[p]; size[2] = nb_ghost_element[p]; size[3] = nb_element_to_send[p]; size[4] = nb_tags; size[5] = names_size; - comm.send(size, 6, p, TAG_SIZES); + AKANTU_DEBUG_INFO("Sending connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")"); + comm.send(size, 6, p, Tag::genTag(my_rank, count, TAG_SIZES)); - AKANTU_DEBUG_INFO("Sending connectivities to proc " << p); + AKANTU_DEBUG_INFO("Sending connectivities to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_CONNECTIVITY) <<")"); requests.push_back(comm.asyncSend(buffers[p], nb_nodes_per_element * (nb_local_element[p] + nb_ghost_element[p]), - p, TAG_CONNECTIVITY)); + p, Tag::genTag(my_rank, count, TAG_CONNECTIVITY))); } else { local_connectivity = buffers[p]; } } /// create the renumbered connectivity AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, local_connectivity, nb_local_element[root], nb_ghost_element[root], type, *old_nodes); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { delete [] buffers[p]; } /* -------------------------------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { buffers[p] = new UInt[nb_ghost_element[p] + nb_element_to_send[p]]; buffers_tmp[p] = buffers[p]; } /// splitting the partition information to send them to processors UInt count_by_proc[nb_proc]; memset(count_by_proc, 0, nb_proc*sizeof(UInt)); for (UInt el = 0; el < nb_element; ++el) { *(buffers_tmp[partition_num[el]]++) = ghost_partition_offset[el + 1] - ghost_partition_offset[el]; for (UInt part = ghost_partition_offset[el], i = 0; part < ghost_partition_offset[el + 1]; ++part, ++i) { *(buffers_tmp[partition_num[el]]++) = ghost_partition[part]; } } for (UInt el = 0; el < nb_element; ++el) { for (UInt part = ghost_partition_offset[el], i = 0; part < ghost_partition_offset[el + 1]; ++part, ++i) { *(buffers_tmp[ghost_partition[part]]++) = partition_num[el]; } } /* -------->>>>-PARTITIONS--------------------------------------------- */ /// last data to compute the communication scheme for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { - AKANTU_DEBUG_INFO("Sending partition informations to proc " << p); + AKANTU_DEBUG_INFO("Sending partition informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_PARTITIONS) <<")"); requests.push_back(comm.asyncSend(buffers[p], nb_element_to_send[p] + nb_ghost_element[p], - p, TAG_PARTITIONS)); + p, Tag::genTag(my_rank, count, TAG_PARTITIONS))); } else { local_partitions = buffers[p]; } } AKANTU_DEBUG_INFO("Creating communications scheme"); - communicator->fillCommunicationScheme(local_partitions, - nb_local_element[root], - nb_ghost_element[root], - type); + communicator.fillCommunicationScheme(local_partitions, + nb_local_element[root], + nb_ghost_element[root], + type); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { delete [] buffers[p]; } /* -------------------------------------------------------------------- */ /// send int data assossiated to the mesh if(nb_tags) { UInt uint_names_size = names_size / sizeof(UInt) + (names_size % sizeof(UInt) ? 1 : 0); for (UInt p = 0; p < nb_proc; ++p) { UInt size = nb_tags * (nb_local_element[p] + nb_ghost_element[p]) + uint_names_size; buffers[p] = new UInt[size]; std::fill_n(buffers[p], size, 0); buffers_tmp[p] = buffers[p]; } char * names = new char[names_size]; char * names_tmp = names; memset(names, 0, names_size); for(it_data = uint_data_map.begin(); it_data != uint_data_map.end(); ++it_data) { UInt * data = it_data->second->values; memcpy(names_tmp, it_data->first.data(), it_data->first.size()); names_tmp += it_data->first.size() + 1; /// copying data for the local element for (UInt el = 0; el < nb_element; ++el) { UInt proc = partition_num[el]; *(buffers_tmp[proc]) = data[el]; buffers_tmp[proc]++; } /// copying the data for the ghost element for (UInt el = 0; el < nb_element; ++el) { for (UInt part = ghost_partition_offset[el]; part < ghost_partition_offset[el + 1]; ++part) { UInt proc = ghost_partition[part]; *(buffers_tmp[proc]) = data[el]; buffers_tmp[proc]++; } } } /* -------->>>>-TAGS------------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { memcpy((char *)buffers_tmp[p], names, names_size); if(p != root) { UInt size = nb_tags * (nb_local_element[p] + nb_ghost_element[p]) + uint_names_size; - AKANTU_DEBUG_INFO("Sending associated data to proc " << p); - requests.push_back(comm.asyncSend(buffers[p], size, p, TAG_DATA)); + AKANTU_DEBUG_INFO("Sending associated data to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_DATA) <<")"); + requests.push_back(comm.asyncSend(buffers[p], size, p, Tag::genTag(my_rank, count, TAG_DATA))); } else { local_data = buffers[p]; } } MeshUtils::setUIntData(mesh, local_data, nb_tags, type); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) delete [] buffers[p]; delete [] names; } + ++count; } /* -------->>>>-SIZE----------------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { UInt size[6]; size[0] = (UInt) _not_defined; size[1] = 0; size[2] = 0; size[3] = 0; size[4] = 0; size[5] = 0; - comm.send(size, 6, p, TAG_SIZES); + AKANTU_DEBUG_INFO("Sending empty connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")"); + comm.send(size, 6, p, Tag::genTag(my_rank, count, TAG_SIZES)); } } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /** * Nodes coordinate construction and synchronization */ std::multimap< UInt, std::pair<UInt, UInt> > nodes_to_proc; /// get the list of nodes to send and send them Real * local_nodes = NULL; UInt nb_nodes_per_proc[nb_proc]; UInt * nodes_per_proc[nb_proc]; /* --------<<<<-NB_NODES + NODES----------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { UInt nb_nodes = 0; // UInt * buffer; if(p != root) { - AKANTU_DEBUG_INFO("Receiving list of nodes from proc " << p); - comm.receive(&nb_nodes, 1, p, TAG_NB_NODES); + AKANTU_DEBUG_INFO("Receiving number of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NB_NODES) <<")"); + comm.receive(&nb_nodes, 1, p, Tag::genTag(p, 0, TAG_NB_NODES)); nodes_per_proc[p] = new UInt[nb_nodes]; nb_nodes_per_proc[p] = nb_nodes; - comm.receive(nodes_per_proc[p], nb_nodes, p, TAG_NODES); + AKANTU_DEBUG_INFO("Receiving list of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NODES) <<")"); + comm.receive(nodes_per_proc[p], nb_nodes, p, Tag::genTag(p, 0, TAG_NODES)); } else { nb_nodes = old_nodes->getSize(); nb_nodes_per_proc[p] = nb_nodes; nodes_per_proc[p] = old_nodes->values; } /// get the coordinates for the selected nodes Real * nodes_to_send = new Real[nb_nodes * spatial_dimension]; Real * nodes_to_send_tmp = nodes_to_send; for (UInt n = 0; n < nb_nodes; ++n) { memcpy(nodes_to_send_tmp, nodes->values + spatial_dimension * nodes_per_proc[p][n], spatial_dimension * sizeof(Real)); // nodes_to_proc.insert(std::make_pair(buffer[n], std::make_pair(p, n))); nodes_to_send_tmp += spatial_dimension; } /* -------->>>>-COORDINATES-------------------------------------------- */ if(p != root) { /// send them for distant processors - AKANTU_DEBUG_INFO("Sending coordinates to proc " << p); - comm.send(nodes_to_send, nb_nodes * spatial_dimension, p, TAG_COORDINATES); + AKANTU_DEBUG_INFO("Sending coordinates to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_COORDINATES) <<")"); + comm.send(nodes_to_send, nb_nodes * spatial_dimension, p, Tag::genTag(my_rank, 0, TAG_COORDINATES)); delete [] nodes_to_send; } else { /// save them for local processor local_nodes = nodes_to_send; } } /// construct the local nodes coordinates UInt nb_nodes = old_nodes->getSize(); nodes->resize(nb_nodes); memcpy(nodes->values, local_nodes, nb_nodes * spatial_dimension * sizeof(Real)); delete [] local_nodes; Vector<Int> * nodes_type_per_proc[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { nodes_type_per_proc[p] = new Vector<Int>(nb_nodes_per_proc[p]); } - communicator->fillNodesType(mesh); + communicator.fillNodesType(mesh); /* --------<<<<-NODES_TYPE-1--------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { - AKANTU_DEBUG_INFO("Receiving first nodes types from proc " << p); + AKANTU_DEBUG_INFO("Receiving first nodes types from proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_NODES_TYPE) <<")"); comm.receive(nodes_type_per_proc[p]->values, - nb_nodes_per_proc[p], p, TAG_NODES_TYPE); + nb_nodes_per_proc[p], p, Tag::genTag(p, 0, TAG_NODES_TYPE)); } else { nodes_type_per_proc[p]->copy(mesh.getNodesType()); } for (UInt n = 0; n < nb_nodes_per_proc[p]; ++n) { if((*nodes_type_per_proc[p])(n) == -2) nodes_to_proc.insert(std::make_pair(nodes_per_proc[p][n], std::make_pair(p, n))); } } std::multimap< UInt, std::pair<UInt, UInt> >::iterator it_node; std::pair< std::multimap< UInt, std::pair<UInt, UInt> >::iterator, std::multimap< UInt, std::pair<UInt, UInt> >::iterator > it_range; for (UInt i = 0; i < mesh.nb_global_nodes; ++i) { it_range = nodes_to_proc.equal_range(i); if(it_range.first == nodes_to_proc.end() || it_range.first->first != i) continue; UInt node_type = (it_range.first)->second.first; for (it_node = it_range.first; it_node != it_range.second; ++it_node) { UInt proc = it_node->second.first; UInt node = it_node->second.second; if(proc != node_type) nodes_type_per_proc[proc]->values[node] = node_type; } } /* -------->>>>-NODES_TYPE-2--------------------------------------------- */ std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { - AKANTU_DEBUG_INFO("Sending nodes types to proc " << p); + AKANTU_DEBUG_INFO("Sending nodes types to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_NODES_TYPE) <<")"); requests.push_back(comm.asyncSend(nodes_type_per_proc[p]->values, - nb_nodes_per_proc[p], p, TAG_NODES_TYPE)); + nb_nodes_per_proc[p], p, Tag::genTag(my_rank, 0, TAG_NODES_TYPE))); } else { mesh.getNodesTypePointer()->copy(*nodes_type_per_proc[p]); } } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { if(p != root) delete [] nodes_per_proc[p]; delete nodes_type_per_proc[p]; } /* ---------------------------------------------------------------------- */ /* Distant (rank != root) */ /* ---------------------------------------------------------------------- */ } else { /** * connectivity and communications scheme construction on distant processors */ ElementType type = _not_defined; + UInt count = 0; do { /* --------<<<<-SIZE--------------------------------------------------- */ UInt size[6] = { 0 }; - comm.receive(size, 6, root, TAG_SIZES); + comm.receive(size, 6, root, Tag::genTag(root, count, TAG_SIZES)); type = (ElementType) size[0]; UInt nb_local_element = size[1]; UInt nb_ghost_element = size[2]; UInt nb_element_to_send = size[3]; UInt nb_tags = size[4]; UInt names_size = size[5]; UInt uint_names_size = names_size / sizeof(UInt) + (names_size % sizeof(UInt) ? 1 : 0); if(type != _not_defined) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); /* --------<<<<-CONNECTIVITY----------------------------------------- */ local_connectivity = new UInt[(nb_local_element + nb_ghost_element) * nb_nodes_per_element]; AKANTU_DEBUG_INFO("Receiving connectivities from proc " << root); comm.receive(local_connectivity, nb_nodes_per_element * (nb_local_element + nb_ghost_element), - root, TAG_CONNECTIVITY); + root, Tag::genTag(root, count, TAG_CONNECTIVITY)); AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, local_connectivity, nb_local_element, nb_ghost_element, type, *old_nodes); delete [] local_connectivity; /* --------<<<<-PARTITIONS--------------------------------------------- */ local_partitions = new UInt[nb_element_to_send + nb_ghost_element * 2]; AKANTU_DEBUG_INFO("Receiving partition informations from proc " << root); comm.receive(local_partitions, - nb_element_to_send + nb_ghost_element * 2, - root, TAG_PARTITIONS); + nb_element_to_send + nb_ghost_element * 2, + root, Tag::genTag(root, count, TAG_PARTITIONS)); AKANTU_DEBUG_INFO("Creating communications scheme"); - communicator->fillCommunicationScheme(local_partitions, + communicator.fillCommunicationScheme(local_partitions, nb_local_element, nb_ghost_element, type); delete [] local_partitions; /* --------<<<<-TAGS------------------------------------------------- */ if(nb_tags) { AKANTU_DEBUG_INFO("Receiving associated data from proc " << root); UInt size_data = (nb_local_element + nb_ghost_element) * nb_tags + uint_names_size; local_data = new UInt[size_data]; - comm.receive(local_data, size_data, root, TAG_DATA); + comm.receive(local_data, size_data, root, Tag::genTag(root, count, TAG_DATA)); MeshUtils::setUIntData(mesh, local_data, nb_tags, type); delete [] local_data; } } + ++count; } while(type != _not_defined); /** * Nodes coordinate construction and synchronization on distant processors */ /* -------->>>>-NB_NODES + NODES----------------------------------------- */ AKANTU_DEBUG_INFO("Sending list of nodes to proc " << root); UInt nb_nodes = old_nodes->getSize(); - comm.send(&nb_nodes, 1, root, TAG_NB_NODES); - comm.send(old_nodes->values, nb_nodes, root, TAG_NODES); + comm.send(&nb_nodes, 1, root, Tag::genTag(my_rank, 0, TAG_NB_NODES)); + comm.send(old_nodes->values, nb_nodes, root, Tag::genTag(my_rank, 0, TAG_NODES)); /* --------<<<<-COORDINATES---------------------------------------------- */ nodes->resize(nb_nodes); AKANTU_DEBUG_INFO("Receiving coordinates from proc " << root); - comm.receive(nodes->values, nb_nodes * spatial_dimension, root, TAG_COORDINATES); + comm.receive(nodes->values, nb_nodes * spatial_dimension, root, Tag::genTag(root, 0, TAG_COORDINATES)); - communicator->fillNodesType(mesh); + communicator.fillNodesType(mesh); /* --------<<<<-NODES_TYPE-2--------------------------------------------- */ Int * nodes_types = mesh.getNodesTypePointer()->values; AKANTU_DEBUG_INFO("Sending first nodes types to proc " << root); comm.send(nodes_types, nb_nodes, - root, TAG_NODES_TYPE); + root, Tag::genTag(my_rank, 0, TAG_NODES_TYPE)); /* --------<<<<-NODES_TYPE-2--------------------------------------------- */ AKANTU_DEBUG_INFO("Receiving nodes types from proc " << root); comm.receive(nodes_types, nb_nodes, - root, TAG_NODES_TYPE); + root, Tag::genTag(root, 0, TAG_NODES_TYPE)); } comm.broadcast(&(mesh.nb_global_nodes), 1, root); AKANTU_DEBUG_OUT(); - return communicator; + return &communicator; } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::fillNodesType(Mesh & mesh) { AKANTU_DEBUG_IN(); // StaticCommunicator * comm = StaticCommunicator::getStaticCommunicator(); // UInt my_rank = comm.whoAmI(); UInt nb_nodes = mesh.getNbNodes(); // std::cout << nb_nodes << std::endl; Int * nodes_type = mesh.getNodesTypePointer()->values; //memcpy(nodes_type, nodes_type_tmp, nb_nodes * sizeof(Int)); UInt * nodes_set = new UInt[nb_nodes]; std::fill_n(nodes_set, nb_nodes, 0); // Mesh::ConnectivityTypeList::const_iterator it; const UInt NORMAL_SET = 1; const UInt GHOST_SET = 2; bool * already_seen = new bool[nb_nodes]; for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; UInt set = NORMAL_SET; if (gt == _ghost) set = GHOST_SET; std::fill_n(already_seen, nb_nodes, false); Mesh::type_iterator it = mesh.firstType(0, gt); Mesh::type_iterator end = mesh.lastType(0, gt); for(; it != end; ++it) { ElementType type = *it; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type, gt); UInt * conn_val = mesh.getConnectivity(type, gt).values; for (UInt e = 0; e < nb_element; ++e) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { AKANTU_DEBUG_ASSERT(*conn_val < nb_nodes, "Node " << *conn_val << " bigger than number of nodes " << nb_nodes); if(!already_seen[*conn_val]) { nodes_set[*conn_val] += set; already_seen[*conn_val] = true; } conn_val++; } } } } delete [] already_seen; for (UInt i = 0; i < nb_nodes; ++i) { if(nodes_set[i] == NORMAL_SET) nodes_type[i] = -1; else if(nodes_set[i] == GHOST_SET) nodes_type[i] = -3; else if(nodes_set[i] == (GHOST_SET + NORMAL_SET)) nodes_type[i] = -2; } delete [] nodes_set; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::fillCommunicationScheme(UInt * partition, UInt nb_local_element, UInt nb_ghost_element, ElementType type) { AKANTU_DEBUG_IN(); Element element; element.type = type; UInt * part = partition; part = partition; for (UInt lel = 0; lel < nb_local_element; ++lel) { UInt nb_send = *part; part++; element.element = lel; - element.ghost_type = _ghost; + element.ghost_type = _not_ghost; for (UInt p = 0; p < nb_send; ++p) { UInt proc = *part; part++; AKANTU_DEBUG(dblAccessory, "Must send : " << element << " to proc " << proc); (send_element[proc]).push_back(element); } } for (UInt gel = 0; gel < nb_ghost_element; ++gel) { UInt proc = *part; part++; element.element = gel; - element.ghost_type = _not_ghost; + element.ghost_type = _ghost; AKANTU_DEBUG(dblAccessory, "Must recv : " << element << " from proc " << proc); recv_element[proc].push_back(element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::asynchronousSynchronize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); if (communications.find(tag) == communications.end()) { communications[tag].resize(nb_proc); computeBufferSize(data_accessor, tag); } Communication & communication = communications[tag]; AKANTU_DEBUG_ASSERT(communication.send_requests.size() == 0, "There must be some pending sending communications. Tag is " << tag); for (UInt p = 0; p < nb_proc; ++p) { UInt ssize = communication.size_to_send[p]; if(p == rank || ssize == 0) continue; CommunicationBuffer & buffer = communication.send_buffer[p]; buffer.resize(ssize); #ifndef AKANTU_NDEBUG -#endif - Element * elements = &(send_element[p].at(0)); - UInt nb_elements = send_element[p].size(); + //Element * elements = &(send_element[p](0)); + UInt nb_elements = send_element[p].getSize(); AKANTU_DEBUG_INFO("Packing data for proc " << p << " (" << ssize << "/" << nb_elements <<" data to send/elements)"); +#endif - for (UInt el = 0; el < nb_elements; ++el) { - data_accessor.packData(buffer, *elements, tag); - elements++; - } + data_accessor.packElementData(buffer, send_element[p], tag); + // for (UInt el = 0; el < nb_elements; ++el) { + // data_accessor.packData(buffer, *elements, tag); + // elements++; + // } #ifndef AKANTU_NDEBUG // UInt block_size = data_accessor.getNbDataToPack(send_element[p][0], tag); // AKANTU_DEBUG_WARNING("tag is " << tag << ", packed buffer is " // << buffer.extractStream<Real>(block_size) // << std::endl); #endif AKANTU_DEBUG_ASSERT(buffer.getPackedSize() == ssize, "a problem have been introduced with " << "false sent sizes declaration " << buffer.getPackedSize() << " != " << ssize); std::cerr << std::dec; AKANTU_DEBUG_INFO("Posting send to proc " << p); communication.send_requests.push_back(static_communicator->asyncSend(buffer.storage(), ssize, p, (Int) tag)); } AKANTU_DEBUG_ASSERT(communication.recv_requests.size() == 0, "There must be some pending receive communications"); for (UInt p = 0; p < nb_proc; ++p) { UInt rsize = communication.size_to_receive[p]; if(p == rank || rsize == 0) continue; CommunicationBuffer & buffer = communication.recv_buffer[p]; buffer.resize(rsize); AKANTU_DEBUG_INFO("Posting receive from proc " << p << " (" << rsize << " data to receive)"); communication.recv_requests.push_back(static_communicator->asyncReceive(buffer.storage(), rsize, p, (Int) tag)); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::waitEndSynchronize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(communications.find(tag) != communications.end(), "No communication with the tag \"" << tag <<"\" started"); Communication & communication = communications[tag]; std::vector<CommunicationRequest *> req_not_finished; std::vector<CommunicationRequest *> * req_not_finished_tmp = &req_not_finished; std::vector<CommunicationRequest *> * recv_requests_tmp = &(communication.recv_requests); // static_communicator->waitAll(recv_requests); while(!recv_requests_tmp->empty()) { for (std::vector<CommunicationRequest *>::iterator req_it = recv_requests_tmp->begin(); req_it != recv_requests_tmp->end() ; ++req_it) { CommunicationRequest * req = *req_it; if(static_communicator->testRequest(req)) { UInt proc = req->getSource(); AKANTU_DEBUG_INFO("Unpacking data coming from proc " << proc); CommunicationBuffer & buffer = communication.recv_buffer[proc]; - Element * elements = &recv_element[proc].at(0); - UInt nb_elements = recv_element[proc].size(); - UInt el = 0; - try { - for (el = 0; el < nb_elements; ++el) { - data_accessor.unpackData(buffer, *elements, tag); - elements++; - } - } - catch (debug::Exception & e){ - UInt block_size = data_accessor.getNbDataToPack(recv_element[proc][0], tag); - AKANTU_DEBUG_ERROR("catched exception during unpack from proc " << proc - << " buffer index is " << el << "/" << nb_elements - << std::endl << e.what() << std::endl - << "buffer size " << buffer.getSize() << std::endl - << buffer.extractStream<Real>(block_size)); - } + data_accessor.unpackElementData(buffer, recv_element[proc], tag); + // Element * elements = &recv_element[proc].at(0); + // UInt nb_elements = recv_element[proc].size(); + // UInt el = 0; + // try { + // for (el = 0; el < nb_elements; ++el) { + // data_accessor.unpackData(buffer, *elements, tag); + // elements++; + // } + // } + // catch (debug::Exception & e){ + // UInt block_size = data_accessor.getNbDataToPack(recv_element[proc][0], tag); + // AKANTU_DEBUG_ERROR("catched exception during unpack from proc " << proc + // << " buffer index is " << el << "/" << nb_elements + // << std::endl << e.what() << std::endl + // << "buffer size " << buffer.getSize() << std::endl + // << buffer.extractStream<Real>(block_size)); + // } buffer.resize(0); AKANTU_DEBUG_ASSERT(buffer.getLeftToUnpack() == 0, "all data have not been unpacked: " << buffer.getLeftToUnpack() << " bytes left"); static_communicator->freeCommunicationRequest(req); } else { req_not_finished_tmp->push_back(req); } } std::vector<CommunicationRequest *> * swap = req_not_finished_tmp; req_not_finished_tmp = recv_requests_tmp; recv_requests_tmp = swap; req_not_finished_tmp->clear(); } - static_communicator->waitAll(communication.send_requests); for (std::vector<CommunicationRequest *>::iterator req_it = communication.send_requests.begin(); req_it != communication.send_requests.end() ; ++req_it) { CommunicationRequest & req = *(*req_it); if(static_communicator->testRequest(&req)) { UInt proc = req.getDestination(); CommunicationBuffer & buffer = communication.send_buffer[proc]; buffer.resize(0); static_communicator->freeCommunicationRequest(&req); } } communication.send_requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); // AKANTU_DEBUG_ASSERT(size_to_send.find(tag) == size_to_send.end(), // "The SynchronizationTag< " << tag // << "is already registered in " << id); for (UInt p = 0; p < nb_proc; ++p) { UInt ssend = 0; UInt sreceive = 0; if(p != rank) { - for (std::vector<Element>::const_iterator sit = send_element[p].begin(); - sit != send_element[p].end(); - ++sit) { - ssend += data_accessor.getNbDataToPack(*sit, tag); - } - - for (std::vector<Element>::const_iterator rit = recv_element[p].begin(); - rit != recv_element[p].end(); - ++rit) { - sreceive += data_accessor.getNbDataToUnpack(*rit, tag); - } + ssend = data_accessor.getNbDataForElements(send_element[p], tag); + sreceive = data_accessor.getNbDataForElements(recv_element[p], tag); + // for (std::vector<Element>::const_iterator sit = send_element[p].begin(); + // sit != send_element[p].end(); + // ++sit) { + // ssend += data_accessor.getNbDataToPack(*sit, tag); + // } + + // for (std::vector<Element>::const_iterator rit = recv_element[p].begin(); + // rit != recv_element[p].end(); + // ++rit) { + // sreceive += data_accessor.getNbDataToUnpack(*rit, tag); + // } AKANTU_DEBUG_INFO("I have " << ssend << "(" << ssend / 1024. - << "kB) data to send to " << p + << "kB - "<< send_element[p].getSize() <<" element(s)) data to send to " << p << " and " << sreceive << "(" << sreceive / 1024. - << "kB) data to receive for tag " << tag); + << "kB - "<< recv_element[p].getSize() <<" element(s)) data to receive for tag " << tag); } communications[tag].size_to_send [p] = ssend; communications[tag].size_to_receive[p] = sreceive; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); Int prank = StaticCommunicator::getStaticCommunicator().whoAmI(); Int psize = StaticCommunicator::getStaticCommunicator().getNbProc(); stream << "[" << prank << "/" << psize << "]" << space << "DistributedSynchronizer [" << std::endl; for (UInt p = 0; p < nb_proc; ++p) { if (p == UInt(prank)) continue; stream << "[" << prank << "/" << psize << "]" << space << " + Communication to proc " << p << " [" << std::endl; if(AKANTU_DEBUG_TEST(dblDump)) { stream << "[" << prank << "/" << psize << "]" << space << " - Element to send to proc " << p << " [" << std::endl; - std::vector<Element>::const_iterator it_el = send_element[p].begin(); - std::vector<Element>::const_iterator end_el = send_element[p].end(); + Vector<Element>::iterator<Element> it_el = send_element[p].begin(); + Vector<Element>::iterator<Element> end_el = send_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " - Element to recv from proc " << p << " [" << std::endl; it_el = recv_element[p].begin(); end_el = recv_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl;stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; } std::map< SynchronizationTag, Communication>::const_iterator it = communications.begin(); std::map< SynchronizationTag, Communication>::const_iterator end = communications.end(); for (; it != end; ++it) { const SynchronizationTag & tag = it->first; const Communication & communication = it->second; UInt ssend = communication.size_to_send[p]; UInt sreceive = communication.size_to_receive[p]; stream << "[" << prank << "/" << psize << "]" << space << " - Tag " << tag << " -> " << ssend << "byte(s) -- <- " << sreceive << "byte(s)" << std::endl; } std::cout << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; } std::cout << "[" << prank << "/" << psize << "]" << space << "]" << std::endl; } - /* -------------------------------------------------------------------------- */ +void DistributedSynchronizer::onElementsRemoved(const Vector<Element> & element_to_remove, + const ByElementTypeUInt & new_numbering) { + AKANTU_DEBUG_IN(); + + StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + UInt psize = comm.getNbProc(); + UInt prank = comm.whoAmI(); + + std::vector<CommunicationRequest *> isend_requests; + // Handling ghost elements + for (UInt p = 0; p < psize; ++p) { + if (p == prank) continue; + + Vector<Element> & recv = recv_element[p]; + Vector<UInt> list_of_el_to_remove; + list_of_el_to_remove.push_back(UInt(-1)); + + Vector<Element>::iterator<Element> recv_begin = recv.begin(); + Vector<Element>::iterator<Element> recv_end = recv.end(); + + Vector<Element>::const_iterator<Element> it = element_to_remove.begin(); + Vector<Element>::const_iterator<Element> end = element_to_remove.end(); + for (;it != end; ++it) { + const Element & el = *it; + if(el.ghost_type == _ghost) { + Vector<Element>::iterator<Element> pos = std::find(recv_begin, recv_end, el); + if(pos != recv_end) { + UInt i = pos - recv_begin; + list_of_el_to_remove.push_back(i); + } + } else { + /// \todo handle the removal of element to send from the ghost of other procs + AKANTU_EXCEPTION("DistributedSynchronizer do not know how to remove _not_ghost element, ask a developer to finish is job"); + } + } + std::sort(list_of_el_to_remove.begin(), list_of_el_to_remove.end()); + + isend_requests.push_back(comm.asyncSend(list_of_el_to_remove.storage(), list_of_el_to_remove.getSize(), + p, Tag::genTag(prank, 0, 0))); + + list_of_el_to_remove.resize(list_of_el_to_remove.getSize() - 1); + + Vector<Element> new_recv; + for (UInt nr = 0; nr < recv.getSize(); ++nr) { + Vector<UInt>::iterator<UInt> it = std::find(list_of_el_to_remove.begin(), list_of_el_to_remove.end(), nr); + if(it == list_of_el_to_remove.end()) { + Element & el = recv(nr); + el.element = new_numbering(el.type, el.ghost_type)(el.element); + + new_recv.push_back(el); + } else { list_of_el_to_remove.erase(it - list_of_el_to_remove.begin()); } + } + + recv.resize(new_recv.getSize()); + std::copy(new_recv.begin(), new_recv.end(), recv.begin()); + } + + for (UInt p = 0; p < psize; ++p) { + if (p == prank) continue; + CommunicationStatus status; + comm.probe<UInt>(p, Tag::genTag(p, 0, 0), status); + Vector<UInt> list_of_el_to_remove(status.getSize()); + + comm.receive(list_of_el_to_remove.storage(), list_of_el_to_remove.getSize(), + p, Tag::genTag(p, 0, 0)); + + list_of_el_to_remove.resize(list_of_el_to_remove.getSize() - 1); + + Vector<Element> & send = send_element[p]; + + Vector<Element> new_send; + for (UInt ns = 0; ns < send.getSize(); ++ns) { + Vector<UInt>::iterator<UInt> it = std::find(list_of_el_to_remove.begin(), list_of_el_to_remove.end(), ns); + if(it == list_of_el_to_remove.end()) { + new_send.push_back(send(ns)); + } else { list_of_el_to_remove.erase(it - list_of_el_to_remove.begin()); } + + } + + send.resize(new_send.getSize()); + std::copy(new_send.begin(), new_send.end(), send.begin()); + } + + comm.waitAll(isend_requests); + comm.freeCommunicationRequest(isend_requests); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/synchronizer/distributed_synchronizer.hh b/src/synchronizer/distributed_synchronizer.hh index 4718f9250..04d1b36c7 100644 --- a/src/synchronizer/distributed_synchronizer.hh +++ b/src/synchronizer/distributed_synchronizer.hh @@ -1,178 +1,160 @@ /** * @file distributed_synchronizer.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @date Thu Aug 19 15:28:35 2010 * * @brief wrapper to the static communicator * * @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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ #define __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_vector.hh" #include "static_communicator.hh" #include "synchronizer.hh" #include "mesh.hh" #include "mesh_partition.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class CommunicationBuffer; -class DistributedSynchronizer : public Synchronizer { +class DistributedSynchronizer : public Synchronizer, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ -public: - - DistributedSynchronizer(SynchronizerID id = "distributed_synchronizer", +protected: + DistributedSynchronizer(Mesh & mesh, + SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); + +public: virtual ~DistributedSynchronizer(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get a mesh and a partition and create the local mesh and the associated /// DistributedSynchronizer static DistributedSynchronizer * createDistributedSynchronizerMesh(Mesh & mesh, const MeshPartition * partition, UInt root = 0, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); /* ------------------------------------------------------------------------ */ /* Inherited from Synchronizer */ /* ------------------------------------------------------------------------ */ /// asynchronous synchronization of ghosts void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// wait end of asynchronous synchronization of ghosts void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); virtual void printself(std::ostream & stream, int indent = 0) const; + /// mesh event handler onRemovedElement + virtual void onElementsRemoved(const Vector<Element> & element_list, + const ByElementTypeUInt & new_numbering); + protected: /// fill the nodes type vector void fillNodesType(Mesh & mesh); /// fill the communications array of a distributedSynchronizer based on a partition array void fillCommunicationScheme(UInt * partition, UInt nb_local_element, UInt nb_ghost_element, ElementType type); /// compute buffer size for a given tag and data accessor void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: + /// reference to the underlying mesh + Mesh & mesh; + /// the static memory instance StaticCommunicator * static_communicator; class Communication { public: void resize(UInt size) { send_buffer.resize(size); recv_buffer.resize(size); size_to_send .resize(size); size_to_receive.resize(size); } public: /// size of data to send to each processor std::vector<UInt> size_to_send; /// size of data to recv to each processor std::vector<UInt> size_to_receive; std::vector<CommunicationBuffer> send_buffer; std::vector<CommunicationBuffer> recv_buffer; std::vector<CommunicationRequest *> send_requests; std::vector<CommunicationRequest *> recv_requests; }; std::map<SynchronizationTag, Communication> communications; - // /// size of data to send to each processor by communication tag - // std::map< SynchronizationTag, Vector<UInt> > size_to_send; - - // /// size of data to receive form each processor by communication tag - // std::map< SynchronizationTag, Vector<UInt> > size_to_receive; - - // std::map<SynchronizationTag, CommunicationBuffer *> send_buffer; - // std::map<SynchronizationTag, CommunicationBuffer *> recv_buffer; - - // /// send requests - // std::vector<CommunicationRequest *> send_requests; - // /// receive requests - // std::vector<CommunicationRequest *> recv_requests; - - // /// list of real element to send ordered by type then by receiver processors - // ByElementTypeUInt element_to_send_offset; - // ByElementTypeUInt element_to_send; - - std::vector<Element> * send_element; - std::vector<Element> * recv_element; - - // /// list of ghost element to receive ordered by type then by sender processors - // ByElementTypeUInt element_to_receive_offset; - // ByElementTypeUInt element_to_receive; + /// list of element to sent to proc p + Vector<Element> * send_element; + /// list of element to receive from proc p + Vector<Element> * recv_element; UInt nb_proc; UInt rank; - // /// global node ids - // Vector<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 - // Vector<Int> * nodes_type; - }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ //#include "distributedSynchronizer_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/grid_synchronizer.cc b/src/synchronizer/grid_synchronizer.cc index d65c05d2f..07aba9293 100644 --- a/src/synchronizer/grid_synchronizer.cc +++ b/src/synchronizer/grid_synchronizer.cc @@ -1,472 +1,479 @@ /** * @file grid_synchronizer.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Tue Sep 20 10:30:37 2011 * * @brief implementation of the grid synchronizer * * @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 "grid_synchronizer.hh" #include "aka_grid.hh" #include "mesh.hh" #include "fem.hh" #include "static_communicator.hh" #include "mesh_io.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -GridSynchronizer::GridSynchronizer(const ID & id, +GridSynchronizer::GridSynchronizer(Mesh & mesh, + const ID & id, MemoryID memory_id) : - DistributedSynchronizer(id, memory_id) { + DistributedSynchronizer(mesh, id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class E> GridSynchronizer * GridSynchronizer::createGridSynchronizer(Mesh & mesh, const RegularGrid<E> & grid, SynchronizerID id, MemoryID memory_id) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); - GridSynchronizer * communicator = new GridSynchronizer(id, memory_id); - if(nb_proc == 1) return communicator; + GridSynchronizer & communicator = *(new GridSynchronizer(mesh, id, memory_id)); + if(nb_proc == 1) return &communicator; UInt spatial_dimension = mesh.getSpatialDimension(); Real * bounding_boxes = new Real[2 * spatial_dimension * nb_proc]; Real * my_bounding_box = bounding_boxes + 2 * spatial_dimension * my_rank; // mesh.getLocalLowerBounds(my_bounding_box); // mesh.getLocalUpperBounds(my_bounding_box + spatial_dimension); grid.getLocalLowerBounds(my_bounding_box); grid.getLocalUpperBounds(my_bounding_box + spatial_dimension); Real spacing[spatial_dimension]; grid.getSpacing(spacing); AKANTU_DEBUG_INFO("Exchange of bounding box to detect the overlapping regions."); comm.allGather(bounding_boxes, spatial_dimension * 2); bool * intersects_proc = new bool[nb_proc]; std::fill_n(intersects_proc, nb_proc, true); UInt * first_cells = new UInt[3 * nb_proc]; UInt * last_cells = new UInt[3 * nb_proc]; std::fill_n(first_cells, 3 * nb_proc, 0); std::fill_n(first_cells, 3 * nb_proc, 0); ByElementTypeUInt ** element_per_proc = new ByElementTypeUInt* [nb_proc]; for (UInt p = 0; p < nb_proc; ++p) element_per_proc[p] = NULL; + // check the overlapping between my box and the one from other processors for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; Real * proc_bounding_box = bounding_boxes + 2 * spatial_dimension * p; bool intersects = false; UInt * first_cell_p = first_cells + p * spatial_dimension; UInt * last_cell_p = last_cells + p * spatial_dimension; for (UInt s = 0; s < spatial_dimension; ++s) { + + // check overlapping of grid intersects = Math::intersects(my_bounding_box[s], my_bounding_box[spatial_dimension + s], proc_bounding_box[s], proc_bounding_box[spatial_dimension + s]); intersects_proc[p] &= intersects; if(intersects) { AKANTU_DEBUG_INFO("I intersects with processor " << p << " in direction " << s); // is point 1 of proc p in the dimension s in the range ? bool point1 = Math::is_in_range(proc_bounding_box[s], my_bounding_box[s], my_bounding_box[s+spatial_dimension]); // is point 2 of proc p in the dimension s in the range ? bool point2 = Math::is_in_range(proc_bounding_box[s+spatial_dimension], my_bounding_box[s], my_bounding_box[s+spatial_dimension]); Real start = 0.; Real end = 0.; if(point1 && !point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box[s]; end = my_bounding_box[s+spatial_dimension]; } else if(point1 && point2) { /* |-----------------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box[s]; end = proc_bounding_box[s+spatial_dimension]; } else if(!point1 && point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box[s]; end = proc_bounding_box[s+spatial_dimension]; } first_cell_p[s] = grid.getCell(start + spacing[s]/100., s); last_cell_p [s] = grid.getCell(end - spacing[s]/100., s); } } + //create the list of cells in the overlapping typedef typename RegularGrid<E>::Cell Cell; std::vector<Cell> * cells = new std::vector<Cell>; if(intersects_proc[p]) { AKANTU_DEBUG_INFO("I intersects with processor " << p); Cell cell(grid); // for (UInt i = 0; i < spatial_dimension; ++i) { // if(first_cell_p[i] != 0) --first_cell_p[i]; // if(last_cell_p[i] != 0) ++last_cell_p[i]; // } for (UInt fd = first_cell_p[0]; fd <= last_cell_p[0]; ++fd) { cell.position[0] = fd; if(spatial_dimension == 1) { cell.updateID(); cells->push_back(cell); } else { for (UInt sd = first_cell_p[1]; sd <= last_cell_p[1] ; ++sd) { cell.position[1] = sd; if(spatial_dimension == 2) { cell.updateID(); cells->push_back(cell); } else { for (UInt ld = first_cell_p[2]; fd <= last_cell_p[2] ; ++ld) { cell.position[2] = ld; cell.updateID(); cells->push_back(cell); } } } } } + // get the list of elements in the cells of the overlapping typename std::vector<Cell>::iterator cur_cell = cells->begin(); typename std::vector<Cell>::iterator last_cell = cells->end(); - std::set<E, CompElementLess> * to_send = new std::set<E, CompElementLess>(); + std::set<Element, CompElementLess> * to_send = new std::set<Element, CompElementLess>(); for (; cur_cell != last_cell; ++cur_cell) { typename RegularGrid<E>::const_iterator cur_elem = grid.beginCell(*cur_cell); typename RegularGrid<E>::const_iterator last_elem = grid.endCell(*cur_cell); for (; cur_elem != last_elem; ++cur_elem) { to_send->insert(*cur_elem); } } AKANTU_DEBUG_INFO("I have prepared " << to_send->size() << " elements to send to processor " << p); delete cells; std::stringstream sstr; sstr << "element_per_proc_" << p; element_per_proc[p] = new ByElementTypeUInt(sstr.str(), id); ByElementTypeUInt & elempproc = *(element_per_proc[p]); - typename std::set<E>::iterator elem = to_send->begin(); - typename std::set<E>::iterator last_elem = to_send->end(); + typename std::set<Element>::iterator elem = to_send->begin(); + typename std::set<Element>::iterator last_elem = to_send->end(); for (; elem != last_elem; ++elem) { ElementType type = elem->type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); // /!\ this part must be slow due to the access in the ByElementTypeUInt if(!elempproc.exists(type)) elempproc.alloc(0, nb_nodes_per_element, type, _not_ghost); UInt global_connect[nb_nodes_per_element]; UInt * local_connect = mesh.getConnectivity(type).storage() + elem->element * nb_nodes_per_element; for (UInt i = 0; i < nb_nodes_per_element; ++i) { global_connect[i] = mesh.getNodeGlobalId(local_connect[i]); } elempproc(type).push_back(global_connect); - communicator->send_element[p].push_back(*elem); + communicator.send_element[p].push_back(*elem); } delete to_send; } } AKANTU_DEBUG_INFO("I have finished to compute intersection," << " no it's time to communicate with my neighbors"); - - -#define SIZE_TAG 0 -#define DATA_TAG 1 -#define ASK_NODES_TAG 2 -#define SEND_NODES_TAG 3 - /* tag = |__________21_________|___8____|_3_| - * | proc | num mes| ct| - */ -#define GEN_TAG(proc, msg_count, tag) (((proc & 0x1FFFFF) << 11) + ((msg_count & 0xFF) << 3) + (tag & 0x7)) - /** * Sending loop, sends the connectivity asynchronously to all concerned proc */ std::vector<CommunicationRequest *> isend_requests; for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; if(intersects_proc[p]) { ByElementTypeUInt & elempproc = *(element_per_proc[p]); ByElementTypeUInt::type_iterator it_type = elempproc.firstType(0, _not_ghost); - ByElementTypeUInt::type_iterator last_type = elempproc.lastType(0, _not_ghost); + ByElementTypeUInt::type_iterator last_type = elempproc.lastType (0, _not_ghost); UInt count = 0; for (; it_type != last_type; ++it_type) { Vector<UInt> & conn = elempproc(*it_type, _not_ghost); UInt info[2]; info[0] = (UInt) *it_type; info[1] = conn.getSize() * conn.getNbComponent(); AKANTU_DEBUG_INFO("I have " << conn.getSize() << " elements of type " << *it_type << " to send to processor " << p - << " (communication tag : " << GEN_TAG(my_rank, count, DATA_TAG) << ")"); + << " (communication tag : " << Tag::genTag(my_rank, count, DATA_TAG) << ")"); - isend_requests.push_back(comm.asyncSend(info, 2, p, GEN_TAG(my_rank, count, SIZE_TAG))); + isend_requests.push_back(comm.asyncSend(info, 2, p, Tag::genTag(my_rank, count, SIZE_TAG))); isend_requests.push_back(comm.asyncSend(conn.storage(), conn.getSize() * conn.getNbComponent(), - p, GEN_TAG(my_rank, count, DATA_TAG))); + p, Tag::genTag(my_rank, count, DATA_TAG))); ++count; } UInt info[2]; info[0] = (UInt) _not_defined; info[1] = 0; - isend_requests.push_back(comm.asyncSend(info, 2, p, GEN_TAG(my_rank, count, SIZE_TAG))); + isend_requests.push_back(comm.asyncSend(info, 2, p, Tag::genTag(my_rank, count, SIZE_TAG))); } } /** * Receives the connectivity and store them in the ghosts elements */ Vector<UInt> & global_nodes_ids = const_cast<Vector<UInt> &>(mesh.getGlobalNodesIds()); Vector<Int> & nodes_type = const_cast<Vector<Int> &>(mesh.getNodesType()); std::vector<CommunicationRequest *> isend_nodes_requests; UInt nb_nodes_to_recv[nb_proc]; UInt nb_total_nodes_to_recv = 0; UInt nb_current_nodes = global_nodes_ids.getSize(); NewNodesEvent new_nodes; NewElementsEvent new_elements; + Vector<UInt> * ask_nodes_per_proc = new Vector<UInt>[nb_proc]; + for (UInt p = 0; p < nb_proc; ++p) { nb_nodes_to_recv[p] = 0; if(p == my_rank) continue; - Vector<UInt> ask_nodes; + Vector<UInt> & ask_nodes = ask_nodes_per_proc[p]; UInt count = 0; if(intersects_proc[p]) { ElementType type = _not_defined; do { UInt info[2] = { 0 }; - comm.receive(info, 2, p, GEN_TAG(p, count, SIZE_TAG)); + comm.receive(info, 2, p, Tag::genTag(p, count, SIZE_TAG)); type = (ElementType) info[0]; if(type != _not_defined) { UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type);; UInt nb_element = info[1] / nb_nodes_per_element; Vector<UInt> tmp_conn(nb_element, nb_nodes_per_element); - comm.receive(tmp_conn.storage(), info[1], p, GEN_TAG(p, count, DATA_TAG)); + comm.receive(tmp_conn.storage(), info[1], p, Tag::genTag(p, count, DATA_TAG)); AKANTU_DEBUG_INFO("I will receive " << nb_element << " elements of type " << ElementType(info[0]) << " from processor " << p - << " (communication tag : " << GEN_TAG(p, count, DATA_TAG) << ")"); + << " (communication tag : " << Tag::genTag(p, count, DATA_TAG) << ")"); Vector<UInt> & ghost_connectivity = const_cast<Vector<UInt> &>(mesh.getConnectivity(type, _ghost)); UInt nb_ghost_element = ghost_connectivity.getSize(); Element element(type, 0, _ghost); UInt conn[nb_nodes_per_element]; for (UInt el = 0; el < nb_element; ++el) { UInt nb_node_to_ask_for_elem = 0; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt gn = tmp_conn(el, n); UInt ln = global_nodes_ids.find(gn); if(ln == UInt(-1)) { global_nodes_ids.push_back(gn); nodes_type.push_back(-3); // pure ghost node ln = nb_current_nodes; new_nodes.getList().push_back(ln); ++nb_current_nodes; ask_nodes.push_back(gn); ++nb_node_to_ask_for_elem; } conn[n] = ln; } // all the nodes are already known locally, the element should already exists UInt c = UInt(-1); if(nb_node_to_ask_for_elem == 0) { c = ghost_connectivity.find(conn); element.element = c; } if(c == UInt(-1)) { element.element = nb_ghost_element; ++nb_ghost_element; ghost_connectivity.push_back(conn); new_elements.getList().push_back(element); } - communicator->recv_element[p].push_back(element); + communicator.recv_element[p].push_back(element); } } count++; } while(type != _not_defined); AKANTU_DEBUG_INFO("I have " << ask_nodes.getSize() << " missing nodes for elements coming from processor " << p - << " (communication tag : " << GEN_TAG(my_rank, 0, ASK_NODES_TAG) << ")"); - + << " (communication tag : " << Tag::genTag(my_rank, 0, ASK_NODES_TAG) << ")"); isend_nodes_requests.push_back(comm.asyncSend(ask_nodes.storage(), ask_nodes.getSize(), - p, GEN_TAG(my_rank, 0, ASK_NODES_TAG))); + p, Tag::genTag(my_rank, 0, ASK_NODES_TAG))); nb_nodes_to_recv[p] = ask_nodes.getSize(); nb_total_nodes_to_recv += ask_nodes.getSize(); } } - - Vector<Real> & nodes = const_cast<Vector<Real> &>(mesh.getNodes()); - UInt nb_nodes = nodes.getSize(); - std::vector<CommunicationRequest *> irecv_nodes_requests; - nodes.resize(nb_total_nodes_to_recv + nb_nodes); for (UInt p = 0; p < nb_proc; ++p) { - if((p != my_rank) && (nb_nodes_to_recv[p] > 0)) { - irecv_nodes_requests.push_back(comm.asyncReceive(nodes.storage() + nb_nodes * spatial_dimension, - nb_nodes_to_recv[p] * spatial_dimension, - p, GEN_TAG(p, 0, SEND_NODES_TAG))); - nb_nodes += nb_nodes_to_recv[p]; - } + if(element_per_proc[p]) delete element_per_proc[p]; } - + delete [] element_per_proc; comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); - for (UInt p = 0; p < nb_proc; ++p) { - if(element_per_proc[p]) delete element_per_proc[p]; - } - delete [] element_per_proc; /** * Sends requested nodes to proc */ + Vector<Real> & nodes = const_cast<Vector<Real> &>(mesh.getNodes()); + UInt nb_nodes = nodes.getSize(); + + std::vector<CommunicationRequest *> isend_coordinates_requests; + Vector<Real> * nodes_to_send_per_proc = new Vector<Real>[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { - if(p == my_rank) continue; + if(p == my_rank || !intersects_proc[p]) continue; Vector<UInt> asked_nodes; CommunicationStatus status; - comm.probe<UInt>(p, GEN_TAG(p, 0, ASK_NODES_TAG), status); + AKANTU_DEBUG_INFO("Waiting list of nodes to send to processor " << p + << "(communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); + + comm.probe<UInt>(p, Tag::genTag(p, 0, ASK_NODES_TAG), status); UInt nb_nodes_to_send = status.getSize(); asked_nodes.resize(nb_nodes_to_send); AKANTU_DEBUG_INFO("I have " << nb_nodes_to_send - << " to send to processor " << p - << "(communication tag : " << GEN_TAG(p, 0, ASK_NODES_TAG) << ")"); + << " nodes to send to processor " << p + << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); - comm.receive(asked_nodes.storage(), nb_nodes_to_send, p, GEN_TAG(p, 0, ASK_NODES_TAG)); - Vector<Real> nodes_to_send(0, spatial_dimension); + AKANTU_DEBUG_INFO("Getting list of nodes to send to processor " << p + << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); + + comm.receive(asked_nodes.storage(), nb_nodes_to_send, p, Tag::genTag(p, 0, ASK_NODES_TAG)); + + Vector<Real> & nodes_to_send = nodes_to_send_per_proc[p]; + nodes_to_send.extendComponentsInterlaced(spatial_dimension, 1); for (UInt n = 0; n < nb_nodes_to_send; ++n) { UInt ln = global_nodes_ids.find(asked_nodes(n)); + AKANTU_DEBUG_ASSERT(ln != UInt(-1), "The node [" << asked_nodes(n) << "] requested by proc " << p << " was not found locally!"); nodes_to_send.push_back(nodes.storage() + ln * spatial_dimension); } - comm.send(nodes_to_send.storage(), nb_nodes_to_send * spatial_dimension, p, GEN_TAG(my_rank, 0, SEND_NODES_TAG)); + + AKANTU_DEBUG_INFO("Sending the nodes to processor " << p + << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); + + isend_coordinates_requests.push_back(comm.asyncSend(nodes_to_send.storage(), nb_nodes_to_send * spatial_dimension, p, Tag::genTag(my_rank, 0, SEND_NODES_TAG))); } comm.waitAll(isend_nodes_requests); comm.freeCommunicationRequest(isend_nodes_requests); + delete [] ask_nodes_per_proc; + + // std::vector<CommunicationRequest *> irecv_nodes_requests; + nodes.resize(nb_total_nodes_to_recv + nb_nodes); + for (UInt p = 0; p < nb_proc; ++p) { + if((p != my_rank) && (nb_nodes_to_recv[p] > 0)) { + AKANTU_DEBUG_INFO("Receiving the nodes from processor " << p + << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); - comm.waitAll(irecv_nodes_requests); - comm.freeCommunicationRequest(irecv_nodes_requests); + comm.receive(nodes.storage() + nb_nodes * spatial_dimension, + nb_nodes_to_recv[p] * spatial_dimension, + p, Tag::genTag(p, 0, SEND_NODES_TAG)); + nb_nodes += nb_nodes_to_recv[p]; + } + } + + comm.waitAll(isend_coordinates_requests); + comm.freeCommunicationRequest(isend_coordinates_requests); + delete [] nodes_to_send_per_proc; + + // comm.waitAll(irecv_nodes_requests); + // comm.freeCommunicationRequest(irecv_nodes_requests); mesh.sendEvent(new_nodes); mesh.sendEvent(new_elements); AKANTU_DEBUG_OUT(); - return communicator; + return &communicator; } -/* -------------------------------------------------------------------------- */ -// template <class E> -// GridSynchronizer * GridSynchronizer::cleanupExtraElement(const Vector<Element> & element_to_remove) { -// AKANTU_DEBUG_IN(); - - - - - -// AKANTU_DEBUG_OUT(); -// } - /* -------------------------------------------------------------------------- */ template GridSynchronizer * GridSynchronizer::createGridSynchronizer<QuadraturePoint>(Mesh & mesh, const RegularGrid<QuadraturePoint> & grid, SynchronizerID id, MemoryID memory_id); template GridSynchronizer * GridSynchronizer::createGridSynchronizer<Element>(Mesh & mesh, const RegularGrid<Element> & grid, SynchronizerID id, MemoryID memory_id); __END_AKANTU__ diff --git a/src/synchronizer/grid_synchronizer.hh b/src/synchronizer/grid_synchronizer.hh index 052e2d680..cb9f959a0 100644 --- a/src/synchronizer/grid_synchronizer.hh +++ b/src/synchronizer/grid_synchronizer.hh @@ -1,97 +1,89 @@ /** * @file grid_synchronizer.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Fri Sep 16 15:05:52 2011 * * @brief synchronizer based in RegularGrid * * @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 "distributed_synchronizer.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GRID_SYNCHRONIZER_HH__ #define __AKANTU_GRID_SYNCHRONIZER_HH__ __BEGIN_AKANTU__ class Mesh; template<class T> class RegularGrid; class GridSynchronizer : public DistributedSynchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ -public: - - GridSynchronizer(const ID & id = "grid_synchronizer", MemoryID memory_id = 0); +protected: + GridSynchronizer(Mesh & mesh, const ID & id = "grid_synchronizer", MemoryID memory_id = 0); +public: virtual ~GridSynchronizer() { }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template <class E> static GridSynchronizer * createGridSynchronizer(Mesh & mesh, const RegularGrid<E> & grid, SynchronizerID id = "grid_synchronizer", MemoryID memory_id = 0); - /// function to print the contain of the class - // virtual void printself(std::ostream & stream, int indent = 0) const; + +protected: + enum CommTags { + SIZE_TAG = 0, + DATA_TAG = 1, + ASK_NODES_TAG = 2, + SEND_NODES_TAG = 3 + }; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; -/* -------------------------------------------------------------------------- */ -/* inline functions */ -/* -------------------------------------------------------------------------- */ - -//#include "grid_synchronizer_inline_impl.cc" - -/// standard output stream operator -// inline std::ostream & operator <<(std::ostream & stream, const GridSynchronizer & _this) -// { -// _this.printself(stream); -// return stream; -// } - - __END_AKANTU__ #endif /* __AKANTU_GRID_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/synchronizer.hh b/src/synchronizer/synchronizer.hh index ba96706e9..2821991c1 100644 --- a/src/synchronizer/synchronizer.hh +++ b/src/synchronizer/synchronizer.hh @@ -1,101 +1,129 @@ /** * @file synchronizer.hh * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Mon Aug 23 13:48:37 2010 * * @brief interface for communicator and pbc 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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_HH__ #define __AKANTU_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "data_accessor.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class GhostSynchronizer; } __BEGIN_AKANTU__ class Synchronizer : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Synchronizer(SynchronizerID id = "synchronizer", MemoryID memory_id = 0); virtual ~Synchronizer() { }; virtual void printself(__attribute__((unused)) std::ostream & stream, __attribute__((unused)) int indent = 0) const {}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronize ghosts void synchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// asynchronous synchronization of ghosts virtual void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag) = 0; /// wait end of asynchronous synchronization of ghosts virtual void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag) = 0; /// compute buffer size for a given tag and data accessor virtual void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag)=0; + /** + * tag = |__________20_________|___8____|_4_| + * | proc | num mes| ct| + */ + class Tag { + public: + operator int() { return int(tag); } + + static inline Tag genTag(int proc, UInt msg_count, UInt tag) { + Tag t; + t.tag = (((proc & 0xFFFFF) << 12) + ((msg_count & 0xFF) << 4) + (tag & 0xF)); + return t; + } + + virtual void printself(std::ostream & stream, int indent = 0) const { + stream << (tag >> 12) << ":" << (tag >> 4 & 0xFF) << ":" << (tag & 0xF); + } + + private: + UInt tag; + }; + protected: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the synchronizer SynchronizerID id; }; /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Synchronizer & _this) { _this.printself(stream); return stream; } +inline std::ostream & operator <<(std::ostream & stream, const Synchronizer::Tag & _this) +{ + _this.printself(stream); + return stream; +} + __END_AKANTU__ #endif /* __AKANTU_SYNCHRONIZER_HH__ */ diff --git a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_implicit_1d.cc b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_implicit_1d.cc index 3a4b98355..ed82a9cac 100644 --- a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_implicit_1d.cc +++ b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_implicit_1d.cc @@ -1,184 +1,184 @@ /** * @file test_solid_mechanics_model_implicit_1d.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Mon Feb 21 14:56:16 2011 * * @brief test of traction in implicit * * @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 "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "solid_mechanics_model.hh" #include "material.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER # include "io_helper.hh" #endif //AKANTU_USE_IOHELPER #ifdef AKANTU_USE_SCOTCH #include "mesh_partition_scotch.hh" #endif int main(int argc, char *argv[]) { akantu::initialize(argc, argv); #ifdef AKANTU_USE_IOHELPER akantu::ElementType type = akantu::_segment_2; iohelper::ElemType paraview_type = iohelper::LINE1; #endif //AKANTU_USE_IOHELPER akantu::UInt spatial_dimension = 1; // akantu::UInt max_steps = 10000; // akantu::Real time_factor = 0.2; // akantu::Real epot, ekin; akantu::Mesh mesh(spatial_dimension); akantu::MeshIOMSH mesh_io; mesh_io.read("segment1.msh", mesh); // #ifdef AKANTU_USE_SCOTCH // mesh_io.write("bar1_breorder.msh", mesh); // akantu::MeshPartition * partition = new akantu::MeshPartitionScotch(mesh, spatial_dimension); // partition->reorder(); // delete partition; // mesh_io.write("bar1_reorder.msh", mesh); // #endif akantu::SolidMechanicsModel * model = new akantu::SolidMechanicsModel(mesh); akantu::UInt nb_nodes = model->getFEM().getMesh().getNbNodes(); #ifdef AKANTU_USE_IOHELPER akantu::UInt nb_element = model->getFEM().getMesh().getNbElement(type); #endif //AKANTU_USE_IOHELPER /// model initialization model->initVectors(); /// set vectors to 0 memset(model->getForce().values, 0, spatial_dimension*nb_nodes*sizeof(akantu::Real)); memset(model->getVelocity().values, 0, spatial_dimension*nb_nodes*sizeof(akantu::Real)); memset(model->getAcceleration().values, 0, spatial_dimension*nb_nodes*sizeof(akantu::Real)); memset(model->getDisplacement().values, 0, spatial_dimension*nb_nodes*sizeof(akantu::Real)); model->initModel(); model->readMaterials("material.dat"); model->initMaterials(); model->initImplicit(); std::cout << model->getMaterial(0) << std::endl; /// boundary conditions // akantu::Real eps = 1e-16; // for (akantu::UInt i = 0; i < nb_nodes; ++i) { // if(model->getFEM().getMesh().getNodes().values[spatial_dimension*i] >= (bar_length - bar_length / 10.)) // model->getDisplacement().values[spatial_dimension*i] = (model->getFEM().getMesh().getNodes().values[spatial_dimension*i] - (bar_length - bar_length / 10.)) / 100.; // if(model->getFEM().getMesh().getNodes().values[spatial_dimension*i] <= eps) // model->getBoundary().values[spatial_dimension*i] = true; // if(model->getFEM().getMesh().getNodes().values[spatial_dimension*i + 1] <= eps || // model->getFEM().getMesh().getNodes().values[spatial_dimension*i + 1] >= 1 - eps ) { // model->getBoundary().values[spatial_dimension*i + 1] = true; // } // } // model->getForce().at(0) = -1000; - model->getBoundary().at(0,0) = true; - model->getForce().at(1,0) = 1000; + model->getBoundary()(0,0) = true; + model->getForce()(1,0) = 1000; model->initializeUpdateResidualData(); #ifdef AKANTU_USE_IOHELPER /// initialize the paraview output iohelper::DumperParaview dumper; dumper.SetMode(iohelper::TEXT); dumper.SetPoints(model->getFEM().getMesh().getNodes().values, spatial_dimension, nb_nodes, "implicit"); dumper.SetConnectivity((int *)model->getFEM().getMesh().getConnectivity(type).values, paraview_type, nb_element, iohelper::C_MODE); dumper.AddNodeDataField(model->getDisplacement().values, spatial_dimension, "displacements"); dumper.AddNodeDataField(model->getVelocity().values, spatial_dimension, "velocity"); dumper.AddNodeDataField(model->getForce().values, spatial_dimension, "applied_force"); dumper.AddNodeDataField(model->getResidual().values, spatial_dimension, "forces"); dumper.AddElemDataField(model->getMaterial(0).getStrain(type).values, spatial_dimension*spatial_dimension, "strain"); dumper.AddElemDataField(model->getMaterial(0).getStress(type).values, spatial_dimension*spatial_dimension, "stress"); dumper.SetEmbeddedValue("displacements", 1); dumper.SetEmbeddedValue("applied_force", 1); dumper.SetEmbeddedValue("forces", 1); dumper.SetPrefix("paraview/"); dumper.Init(); // dumper.Dump(); #endif //AKANTU_USE_IOHELPER akantu::debug::setDebugLevel(akantu::dblInfo); akantu::UInt count = 0; model->updateResidual(); #ifdef AKANTU_USE_IOHELPER dumper.Dump(); #endif //AKANTU_USE_IOHELPER while(!model->testConvergenceResidual(1e-1) && (count <= 10)) { std::cout << "Iter : " << ++count << std::endl; model->assembleStiffnessMatrix(); model->solveStatic(); model->getStiffnessMatrix().saveMatrix("Ktmp.mtx"); model->updateResidual(); // model->assembleStiffnessMatrix(); #ifdef AKANTU_USE_IOHELPER dumper.Dump(); #endif //AKANTU_USE_IOHELPER } delete model; akantu::finalize(); return EXIT_SUCCESS; } diff --git a/test/test_synchronizer/test_grid_synchronizer.cc b/test/test_synchronizer/test_grid_synchronizer.cc index 608d5f0b6..689ff8fdd 100644 --- a/test/test_synchronizer/test_grid_synchronizer.cc +++ b/test/test_synchronizer/test_grid_synchronizer.cc @@ -1,339 +1,354 @@ /** * @file test_grid_synchronizer.cc * @author Nicolas Richart <nicolas.richart@epfl.ch> * @date Mon Nov 7 11:58:02 2011 * * @brief test the GridSynchronizer object * * @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_grid.hh" #include "mesh.hh" #include "mesh_io.hh" #include "grid_synchronizer.hh" #include "mesh_partition.hh" #include "synchronizer_registry.hh" #ifdef AKANTU_USE_IOHELPER # include "io_helper.hh" #endif //AKANTU_USE_IOHELPER using namespace akantu; class TestAccessor : public DataAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: TestAccessor(const Mesh & mesh); ~TestAccessor(); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Barycenter, barycenter, Real); /* ------------------------------------------------------------------------ */ /* Ghost Synchronizer inherited members */ /* ------------------------------------------------------------------------ */ protected: - virtual UInt getNbDataToPack(const Element & element, - SynchronizationTag tag) const; - virtual UInt getNbDataToUnpack(const Element & element, - SynchronizationTag tag) const; - virtual void packData(CommunicationBuffer & buffer, - const Element & element, + virtual UInt getNbDataForElements(const Vector<Element> & elements, + SynchronizationTag tag) const; + virtual void packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, SynchronizationTag tag) const; - virtual void unpackData(CommunicationBuffer & buffer, - const Element & element, - SynchronizationTag tag); + virtual void unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: std::string id; ByElementTypeReal barycenter; const Mesh & mesh; }; /* -------------------------------------------------------------------------- */ /* TestSynchronizer implementation */ /* -------------------------------------------------------------------------- */ TestAccessor::TestAccessor(const Mesh & mesh) : barycenter("barycenter", id), mesh(mesh) { UInt spatial_dimension = mesh.getSpatialDimension(); id = "test_synchronizer"; Mesh::ConnectivityTypeList::const_iterator it; try { const Mesh::ConnectivityTypeList & ghost_type_list = mesh.getConnectivityTypeList(_ghost); for(it = ghost_type_list.begin(); it != ghost_type_list.end(); ++it) { if(Mesh::getSpatialDimension(*it) != spatial_dimension) continue; UInt nb_ghost_element = mesh.getNbElement(*it,_ghost); barycenter.alloc(nb_ghost_element, spatial_dimension, *it); } } catch (debug::Exception & e) { std::cout << e << std::endl; } } TestAccessor::~TestAccessor() { } -UInt TestAccessor::getNbDataToPack(const Element & element, - __attribute__ ((unused)) SynchronizationTag tag) const { - return Mesh::getSpatialDimension(element.type) * sizeof(Real); +UInt TestAccessor::getNbDataForElements(const Vector<Element> & elements, + __attribute__ ((unused)) SynchronizationTag tag) const { + return Mesh::getSpatialDimension(elements(0).type) * sizeof(Real) * elements.getSize(); } -UInt TestAccessor::getNbDataToUnpack(const Element & element, - __attribute__ ((unused)) SynchronizationTag tag) const { - return Mesh::getSpatialDimension(element.type) * sizeof(Real); -} - -void TestAccessor::packData(CommunicationBuffer & buffer, - const Element & element, - __attribute__ ((unused)) SynchronizationTag tag) const { - UInt spatial_dimension = Mesh::getSpatialDimension(element.type); - types::RVector bary(spatial_dimension); - mesh.getBarycenter(element.element, element.type, bary.storage()); - - buffer << bary; +void TestAccessor::packElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + __attribute__ ((unused)) SynchronizationTag tag) const { + UInt spatial_dimension = mesh.getSpatialDimension(); + Vector<Element>::const_iterator<Element> bit = elements.begin(); + Vector<Element>::const_iterator<Element> bend = elements.end(); + for (; bit != bend; ++bit) { + const Element & element = *bit; + + types::RVector bary(barycenter(element.type, + element.ghost_type).storage() + element.element * spatial_dimension, + spatial_dimension);; + buffer << barycenter; + } } -void TestAccessor::unpackData(CommunicationBuffer & buffer, - const Element & element, - __attribute__ ((unused)) SynchronizationTag tag) { - UInt spatial_dimension = Mesh::getSpatialDimension(element.type); - Vector<Real>::iterator<types::RVector> bary = - barycenter(element.type).begin(spatial_dimension); - buffer >> bary[element.element]; +void TestAccessor::unpackElementData(CommunicationBuffer & buffer, + const Vector<Element> & elements, + __attribute__ ((unused)) SynchronizationTag tag) { + UInt spatial_dimension = mesh.getSpatialDimension(); + Vector<Element>::const_iterator<Element> bit = elements.begin(); + Vector<Element>::const_iterator<Element> bend = elements.end(); + for (; bit != bend; ++bit) { + const Element & element = *bit; + + types::RVector barycenter_loc(spatial_dimension); + mesh.getBarycenter(element.element, element.type, barycenter_loc.storage(), element.ghost_type); + + types::RVector barycenter(spatial_dimension); + buffer >> barycenter; + Real tolerance = 1e-15; + for (UInt i = 0; i < spatial_dimension; ++i) { + if(!(std::abs(barycenter(i) - barycenter_loc(i)) <= tolerance)) + AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: " + << element + << "(barycenter[" << i << "] = " << barycenter_loc(i) + << " and buffer[" << i << "] = " << barycenter(i) << ") - tag: " << tag); + } + } } /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { akantu::initialize(argc, argv); UInt spatial_dimension = 2; ElementType type = _triangle_3; Mesh mesh(spatial_dimension); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); if(prank == 0) { MeshIOMSH mesh_io; mesh_io.read("triangle.msh", mesh); MeshPartition * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } #ifdef AKANTU_USE_IOHELPER double * part; unsigned int nb_nodes = mesh.getNbNodes(); unsigned int nb_element = mesh.getNbElement(type); iohelper::DumperParaview dumper; dumper.SetMode(iohelper::TEXT); dumper.SetParallelContext(prank, psize); dumper.SetPoints(mesh.getNodes().values, spatial_dimension, nb_nodes, "test-grid-synchronizer"); dumper.SetConnectivity((int*) mesh.getConnectivity(type).values, iohelper::TRIANGLE1, nb_element, iohelper::C_MODE); part = new double[nb_element]; for (unsigned int i = 0; i < nb_element; ++i) part[i] = prank; dumper.AddElemDataField(part, 1, "partitions"); dumper.SetPrefix("paraview/"); dumper.Init(); dumper.Dump(); delete [] part; iohelper::DumperParaview dumper_ghost; dumper_ghost.SetMode(iohelper::TEXT); dumper_ghost.SetParallelContext(prank, psize); try { unsigned int nb_ghost_element = mesh.getNbElement(type,_ghost); dumper_ghost.SetPoints(mesh.getNodes().values, spatial_dimension, nb_nodes, "test-grid-synchronizer-ghost"); dumper_ghost.SetConnectivity((int*) mesh.getConnectivity(type,_ghost).values, iohelper::TRIANGLE1, nb_ghost_element, iohelper::C_MODE); part = new double[nb_ghost_element]; for (unsigned int i = 0; i < nb_ghost_element; ++i) part[i] = prank; dumper_ghost.AddElemDataField(part, 1, "partitions"); dumper_ghost.SetPrefix("paraview/"); dumper_ghost.Init(); dumper_ghost.Dump(); delete [] part; } catch (debug::Exception & e) { std::cout << e << std::endl; } #endif comm.barrier(); mesh.computeBoundingBox(); Real lower_bounds[spatial_dimension]; Real upper_bounds[spatial_dimension]; mesh.getLowerBounds(lower_bounds); mesh.getUpperBounds(upper_bounds); Real spacing[spatial_dimension]; for (UInt i = 0; i < spatial_dimension; ++i) { spacing[i] = (upper_bounds[i] - lower_bounds[i]) / 10.; } Real local_lower_bounds[spatial_dimension]; Real local_upper_bounds[spatial_dimension]; mesh.getLocalLowerBounds(local_lower_bounds); mesh.getLocalUpperBounds(local_upper_bounds); RegularGrid<Element> grid(spatial_dimension, local_lower_bounds, local_upper_bounds, spacing); 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); std::cout << prank << " TTTTTTTOOOOOOOOOOOOOTTTTTTTTTTTTTTTTOOOOOOOOOOOOO" << grid <<std::endl; ByElementTypeReal barycenters("", "", 0); mesh.initByElementTypeVector(barycenters, spatial_dimension, 0); // first generate the quad points coordinate and count the number of points per cell for(; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it); Vector<Real> & barycenter = barycenters(*it); barycenter.resize(nb_element); // Vector<Real>::iterator<types::RVector> bary_it = barycenter.begin(spatial_dimension); // for (UInt elem = 0; elem < nb_element; ++elem) { // // grid.count(*bary_it); // ++bary_it; // } } Element e; e.ghost_type = ghost_type; std::cout << prank << " TTTTTTTOOOOOOOOOOOOOTTTTTTTTTTTTTTTTOOOOOOOOOOOOO" << std::endl; // second insert the point in the cells // grid.beginInsertions(); it = mesh.firstType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it); e.type = *it; Vector<Real> & barycenter = barycenters(*it); Vector<Real>::iterator<types::RVector> bary_it = barycenter.begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem) { mesh.getBarycenter(elem, *it, bary_it->storage()); e.element = elem; grid.insert(e, *bary_it); ++bary_it; } } // grid.endInsertions(); MeshIOMSH mesh_io; std::stringstream sstr; sstr << "mesh_" << prank << ".msh"; mesh_io.write(sstr.str(), mesh); Mesh grid_mesh(spatial_dimension, "grid_mesh", 0); std::stringstream sstr_grid; sstr_grid << "grid_mesh_" << prank << ".msh"; grid.saveAsMesh(grid_mesh); mesh_io.write(sstr_grid.str(), grid_mesh); std::cout << "TTTTTTTOOOOOOOOOOOOOTTTTTTTTTTTTTTTTOOOOOOOOOOOOO" << std::endl; GridSynchronizer * grid_communicator = GridSynchronizer::createGridSynchronizer(mesh, grid); AKANTU_DEBUG_INFO("Creating TestAccessor"); TestAccessor test_accessor(mesh); SynchronizerRegistry synch_registry(test_accessor); synch_registry.registerSynchronizer(*grid_communicator, _gst_test); AKANTU_DEBUG_INFO("Synchronizing tag"); synch_registry.synchronize(_gst_test); #ifdef AKANTU_USE_IOHELPER try { UInt nb_ghost_element = mesh.getNbElement(type, _ghost); UInt nb_nodes = mesh.getNbNodes(); iohelper::DumperParaview dumper_ghost; dumper_ghost.SetMode(iohelper::TEXT); dumper_ghost.SetParallelContext(prank, psize); dumper_ghost.SetMode(iohelper::TEXT); dumper_ghost.SetParallelContext(prank, psize); dumper_ghost.SetPoints(mesh.getNodes().values, spatial_dimension, nb_nodes, "test-grid-synchronizer-ghost"); dumper_ghost.SetConnectivity((int*) mesh.getConnectivity(type,_ghost).values, iohelper::TRIANGLE1, nb_ghost_element, iohelper::C_MODE); part = new double[nb_ghost_element]; for (unsigned int i = 0; i < nb_ghost_element; ++i) part[i] = prank; dumper_ghost.AddElemDataField(part, 1, "partitions"); dumper_ghost.Dump(); delete [] part; unsigned int nb_grid_element = grid_mesh.getNbElement(_quadrangle_4); unsigned int nb_quadrature_points = 4; iohelper::DumperParaview dumper_grid; dumper_grid.SetMode(iohelper::TEXT); dumper_grid.SetParallelContext(prank, psize); dumper_grid.SetPoints(grid_mesh.getNodes().values, spatial_dimension, grid_mesh.getNbNodes(), "test-grid-synchronizer-grid"); dumper_grid.SetConnectivity((int*) grid_mesh.getConnectivity(_quadrangle_4).values, iohelper::QUAD1, nb_grid_element, iohelper::C_MODE); part = new double[nb_grid_element * nb_quadrature_points]; std::fill_n(part, nb_grid_element * nb_quadrature_points, prank); dumper_grid.AddElemDataField(part, 1, "partitions"); dumper_grid.SetPrefix("paraview/"); dumper_grid.Init(); dumper_grid.Dump(); delete [] part; } catch(debug::Exception & e) { std::cout << e << std::endl; } #endif //AKANTU_USE_IOHELPER akantu::finalize(); return EXIT_SUCCESS; }