diff --git a/doc/manual/manual-gettingstarted.tex b/doc/manual/manual-gettingstarted.tex index 13538ecfb..4e5eebbae 100644 --- a/doc/manual/manual-gettingstarted.tex +++ b/doc/manual/manual-gettingstarted.tex @@ -1,450 +1,450 @@ \chapter{Getting Started} \section{Downloading the Code} The \akantu source code can be requested using the form accessible at the URL \url{http://lsms.epfl.ch/akantu}. There, you will be asked to accept the LGPL license terms. \section{Compiling \akantu} \akantu is a \code{cmake} project, so to configure it, you can either follow the usual way: \begin{command} > cd akantu > mkdir build > cd build > ccmake .. [ Set the options that you need ] > make > make install \end{command} \noindent Or, use the \code{Makefile} we added for your convenience to handle the \code{cmake} configuration \begin{command} > cd akantu > make config > make > make install \end{command} \noindent All the \akantu options are documented in Appendix \ref{app:package-dependencies}. \section{Writing a \texttt{main} Function\label{sect:common:main}} \label{sec:writing_main} First of all, \akantu needs to be initialized. The memory management included in the core library handles the correct allocation and de-allocation of vectors, structures and/or objects. Moreover, in parallel computations, the initialization procedure performs the communication setup. This is achieved by a pair of functions (\code{initialize} and \code{finalize}) that are used as follows: \begin{cpp} #include "aka_common.hh" #include "..." using namespace akantu; int main(int argc, char *argv[]) { initialize("input_file.dat", argc, argv); // your code ... finalize(); } \end{cpp} The \code{initialize} function takes the text inpute file and the program parameters which can be parsed by \akantu in due form (see \ref{sect:parser}). Obviously it is necessary to include all files needed in main. In this manual all provided code implies the usage of \code{akantu} as namespace. \section{Creating and Loading a Mesh\label{sect:common:mesh}} In its current state, \akantu supports three types of meshes: Gmsh~\cite{gmsh}, Abaqus~\cite{abaqus} and Diana~\cite{diana}. Once a \code{Mesh} object is created with a given spatial dimension, it can be filled by reading a mesh input file. The method \code{read} of the class \code{Mesh} infers the mesh type from the file extension. If a non-standard file extension is used, the mesh type has to be specified. \begin{cpp} UInt spatial_dimension = 2; Mesh mesh(spatial_dimension); // Reading Gmsh files mesh.read("my_gmsh_mesh.msh"); mesh.read("my_gmsh_mesh", _miot_gmsh); // Reading Abaqus files mesh.read("my_abaqus_mesh.inp"); mesh.read("my_abaqus_mesh", _miot_abaqus); // Reading Diana files mesh.read("my_diana_mesh.dat"); mesh.read("my_diana_mesh", _miot_diana); \end{cpp} The Gmsh reader adds the geometrical and physical tags as mesh data. The physical values are stored as a \code{UInt} data called \code{tag\_0}, if a string name is provided it is stored as a \code{std::string} data named \code{physical\_names}. The geometrical tag is stored as a \code{UInt} data named \code{tag\_1}. The Abaqus reader stores the \code{ELSET} in ElementGroups and the \code{NSET} in NodeGroups. The material assignment can be retrieved from the \code{std::string} mesh data named \code{abaqus\_material}. % \akantu supports meshes generated with Gmsh~\cite{gmsh}, a free % software available at \url{http://geuz.org/gmsh/} where a detailed % documentation can be found. Consequently, this manual will not provide % Gmsh usage directions. Gmsh outputs meshes in \code{.msh} format that can be read % by \akantu. In order to import a mesh, it is necessary to create % a \code{Mesh} object through the following function calls: % \begin{cpp} % UInt spatial_dimension = 2; % Mesh mesh(spatial_dimension); % \end{cpp} % The only parameter that has to be specified by the user is the spatial % dimension of the problem. Now it is possible to read a \code{.msh} file with % a \code{MeshIOMSH} object that takes care of loading a mesh to memory. % This step is carried out by: % \begin{cpp} % mesh.read("square.msh"); % \end{cpp} % where the \code{MeshIOMSH} object is first created before being % used to read the \code{.msh} file. The mesh file name as well as the \code{Mesh} % object must be specified by the user. % The \code{MeshIOMSH} object can also write mesh files. This feature % is useful to save a mesh that has been modified during a % simulation. The \code{write} method takes care of it: % \begin{cpp} % mesh_io.write("square_modified.msh", mesh); % \end{cpp} % which works exactly like the \code{read} method. % \akantu supports also meshes generated by % DIANA (\url{http://tnodiana.com}), but only in reading mode. A similar % procedure applies where the only % difference is that the \code{MeshIODiana} object should be used % instead of the \code{MeshIOMSH} one. Additional mesh readers can be % introduced into \akantu by coding new \code{MeshIO} classes. \section{Using \texttt{Arrays}} Data in \akantu can be stored in data containers implemented by the \code{Array} class. In its most basic usage, the \code{Array} class implemented in \akantu is similar to the \code{vector} class of the Standard Template Library (STL) for C++. A simple \code{Array} containing a sequence of \code{nb\_element} values (of a given type) can be generated with: \begin{cpp} Array<type> example_array(nb_element); \end{cpp} where \code{type} usually is \code{Real}, \code{Int}, \code{UInt} or \code{bool}. Each value is associated to an index, so that data can be accessed by typing: \begin{cpp} type & val = example_array(index) \end{cpp} \code{Arrays} can also contain tuples of values for each index. In that case, the number of components per tuple must be specified at the \code{Array} creation. For example, if we want to create an \code{Array} to store the coordinates (sequences of three values) of ten nodes, the appropriate code is the following: \begin{cpp} UInt nb_nodes = 10; UInt spatial_dimension = 3; Array<Real> position(nb_nodes, spatial_dimension); \end{cpp} In this case the $x$ position of the eighth node number will be given by \code{position(7, 0)} (in C++, numbering starts at 0 and not 1). If the number of components for the sequences is not specified, the default value of 1 is used. Here is a list of some basic operations that can be performed on \code{Array}: \begin{itemize} \item \code{resize(size)} change the size of the \code{Array}. \item \code{clear()} set all entries of the \code{Array} to zero. \item \code{set(t)} set all entries of the \code{Array} to \code{t}. \item \code{copy(const Array<T> $\&$ other)} copy another \code{Array} into the current one. The two \code{Array} should have the same number of components. \item \code{push$\_$back(tuple)} append a tuple with the correct number of components at the end of the \code{Array}. \item \code{erase(i) erase the value at the i-th position.} \item \code{find(value)} search \code{value} in the current \code{Array}. Return position index of the first occurence or $-1$ if not found. \item \code{storage()} Return the address of the allocated memory of the \code{Array}. \end{itemize} \subsection{\texttt{Arrays} iterators} It is very common in \akantu to loop over arrays to perform a specific treatment. This ranges from geometric calculation on nodal quantities to tensor algebra (in constitutive laws for example). The \code{Array} object has the possibility to request iterators in order to make the writing of loops easier and enhance readability. For instance, a loop over the nodal coordinates can be performed like: \begin{cpp} //accessing the nodal coordinates Array (spatial_dimension components) Array<Real> nodes = mesh.getNodes(); //creating the iterators - Array<Real>::vector_iterator it = nodes.begin(spatial_dimension); - Array<Real>::vector_iterator end = nodes.end(spatial_dimension); + auto it = nodes.begin(spatial_dimension); + auto end = nodes.end(spatial_dimension); for (; it != end; ++it){ Vector<Real> & coords = (*it); //do what you need .... } \end{cpp} In that example, each \code{Vector<Real>} is a geometrical array of size \code{spatial\_dimension} and the iteration is conveniently performed by the \code{Array} iterator. The \code{Array} object is intensively used to store second order tensor values. In that case, it should be specified that the returned object type is a matrix when constructing the iterator. This is done when calling the \code{begin} function. For instance, assuming that we have a \code{Array} storing stresses, we can loop over the stored tensors by: \begin{cpp} //creating the iterators Array<Real>::matrix_iterator it = stresses.begin(spatial_dimension,spatial_dimension); Array<Real>::matrix_iterator end = stresses.end(spatial_dimension,spatial_dimension); for (; it != end; ++it){ Matrix<Real> & stress = (*it); //do what you need .... } \end{cpp} In that last example, the \code{Matrix} objects are \code{spatial\_dimension} $\times$ \code{spatial\_dimension} matrices. The light objects \code{Matrix} and \code{Vector} can be used and combined to do most common linear algebra. If the number of component is 1, it is possible to use a scalar\_iterator rather than the vector/matrix one. In general, a mesh consists of several kinds of elements. Consequently, the amount of data to be stored can differ for each element type. The straightforward example is the connectivity array, namely the sequences of nodes belonging to each element (linear triangular elements have fewer nodes than, say, rectangular quadratic elements etc.). A particular data structure called \code{ElementTypeMapArray} is provided to easily manage this kind of data. It consists of a group of \code{Arrays}, each associated to an element type. The following code can retrieve the \code{ElementTypeMapArray} which stores the connectivity arrays for a mesh: \begin{cpp} ElementTypeMapArray<UInt> & connectivities = mesh.getConnectivities(); \end{cpp} Then, the specific array associated to a given element type can be obtained by \begin{cpp} Array<UInt> & connectivity_triangle = connectivities(_triangle_3); \end{cpp} where the first order 3-node triangular element was used in the presented piece of code. \subsection{Vector \& Matrix} The \code{Array} iterators as presented in the previous section can be shaped as \code{Vector} or \code{Matrix}. This objects represent $1^{st}$ and $2^{nd}$ order tensors. As such they come with some functionalities that we will present a bit more into detail in this here. \subsubsection{\texttt{Vector<T>}} \begin{enumerate} \item Accessors: \begin{itemize} \item \code{v(i)} gives the $i^{th}$ component of the vector \code{v} \item \code{v[i]} gives the $i^{th}$ component of the vector \code{v} \item \code{v.size()} gives the number of component \end{itemize} \item Level 1: (results are scalars) \begin{itemize} \item \code{v.norm()} returns the geometrical norm ($L_2$) \item \code{v.norm<N>()} returns the $L_N$ norm defined as $\left(\sum_i |\code{v(i)}|^N\right)^{1/N}$. N can take any positive integer value. There are also some particular values for the most commonly used norms, \code{L\_1} for the Manhattan norm, \code{L\_2} for the geometrical norm and \code{L\_inf} for the norm infinity. \item \code{v.dot(x)} return the dot product of \code{v} and \code{x} \item \code{v.distance(x)} return the geometrical norm of $\code{v} - \code{x}$ \end{itemize} \item Level 2: (results are vectors) \begin{itemize} \item \code{v += s}, \code{v -= s}, \code{v *= s}, \code{v /= s} those are element-wise operators that sum, substract, multiply or divide all the component of \code{v} by the scalar \code{s} \item \code{v += x}, \code{v -= x} sums or substracts the vector \code{x} to/from \code{v} \item \code{v.mul(A, x, alpha)} stores the result of $\alpha \mat{A} \vec{x}$ in \code{v}, $\alpha$ is equal to 1 by default \item \code{v.solve(A, b)} stores the result of the resolution of the system $\mat{A} \vec{x} = \vec{b}$ in \code{v} \item \code{v.crossProduct(v1, v2)} computes the cross product of \code{v1} and \code{v2} and stores the result in \code{v} \end{itemize} \end{enumerate} \subsubsection{\texttt{Matrix<T>}} \begin{enumerate} \item Accessors: \begin{itemize} \item \code{A(i, j)} gives the component $A_{ij}$ of the matrix \code{A} \item \code{A(i)} gives the $i^{th}$ column of the matrix as a \code{Vector} \item \code{A[k]} gives the $k^{th}$ component of the matrix, matrices are stored in a column major way, which means that to access $A_{ij}$, $k = i + j M$ \item \code{A.rows()} gives the number of rows of \code{A} ($M$) \item \code{A.cols()} gives the number of columns of \code{A} ($N$) \item \code{A.size()} gives the number of component in the matrix ($M \times N$) \end{itemize} \item Level 1: (results are scalars) \begin{itemize} \item \code{A.norm()} is equivalent to \code{A.norm<L\_2>()} \item \code{A.norm<N>()} returns the $L_N$ norm defined as $\left(\sum_i\sum_j |\code{A(i,j)}|^N\right)^{1/N}$. N can take any positive integer value. There are also some particular values for the most commonly used norms, \code{L\_1} for the Manhattan norm, \code{L\_2} for the geometrical norm and \code{L\_inf} for the norm infinity. \item \code{A.trace()} return the trace of \code{A} \item \code{A.det()} return the determinant of \code{A} \item \code{A.doubleDot(B)} return the double dot product of \code{A} and \code{B}, $\mat{A}:\mat{B}$ \end{itemize} \item Level 3: (results are matrices) \begin{itemize} \item \code{A.eye(s)}, \code{Matrix<T>::eye(s)} fills/creates a matrix with the $s\mat{I}$ with $\mat{I}$ the identity matrix \item \code{A.inverse(B)} stores $\mat{B}^{-1}$ in \code{A} \item \code{A.transpose()} returns $\mat{A}^{t}$ \item \code{A.outerProduct(v1, v2)} stores $\vec{v_1} \vec{v_2}^{t}$ in \code{A} \item \code{C.mul<t\_A, t\_B>(A, B, alpha)}: stores the result of the product of \code{A} and code{B} time the scalar \code{alpha} in \code{C}. \code{t\_A} and \code{t\_B} are boolean defining if \code{A} and \code{B} should be transposed or not. \begin{tabular}{ccl} \toprule \code{t\_A} & \code{t\_B} & result \\ \midrule false & false & $\mat{C} = \alpha \mat{A} \mat{B}$\\ false & true & $\mat{C} = \alpha \mat{A} \mat{B}^t$\\ true & false & $\mat{C} = \alpha \mat{A}^t \mat{B}$\\ true & true & $\mat{C} = \alpha \mat{A}^t \mat{B}^t$\\ \bottomrule \end{tabular} \item \code{A.eigs(d, V)} this method computes the eigenvalues and eigenvectors of \code{A} and store the results in \code{d} and \code{V} such that $\code{d(i)} = \lambda_i$ and $\code{V(i)} = \vec{v_i}$ with $\mat{A}\vec{v_i} = \lambda_i\vec{v_i}$ and $\lambda_1 > ... > \lambda_i > ... > \lambda_N$ \end{itemize} \end{enumerate} \subsubsection{\texttt{Tensor3<T>}} Accessors: \begin{itemize} \item \code{t(i, j, k)} gives the component $T_{ijk}$ of the tensor \code{t} \item \code{t(k)} gives the $k^{th}$ two-dimensional tensor as a \code{Matrix} \item \code{t[k]} gives the $k^{th}$ two-dimensional tensor as a \code{Matrix} \end{itemize} \section{Manipulating group of nodes and/or elements\label{sect:common:groups}} \akantu provides the possibility to manipulate subgroups of elements and nodes. Any \code{ElementGroup} and/or \code{NodeGroup} must be managed by a \code{GroupManager}. Such a manager has the role to associate group objects to names. This is a useful feature, in particular for the application of the boundary conditions, as will be demonstrated in section \ref{sect:smm:boundary}. To most general group manager is the \code{Mesh} class which inheritates from the \code{GroupManager} class. For instance, the following code shows how to request an element group to a mesh: \begin{cpp} // request creation of a group of nodes NodeGroup & my_node_group = mesh.createNodeGroup("my_node_group"); // request creation of a group of elements ElementGroup & my_element_group = mesh.createElementGroup("my_element_group"); /* fill and use the groups */ \end{cpp} \subsection{The \texttt{NodeGroup} object} A group of nodes is stored in \code{NodeGroup} objects. They are quite simple objects which store the indexes of the selected nodes in a \code{Array<UInt>}. Nodes are selected by adding them when calling \code{NodeGroup::add}. For instance you can select nodes having a positive $X$ coordinate with the following code: \begin{cpp} Array<Real> & nodes = mesh.getNodes(); NodeGroup & group = mesh.createNodeGroup("XpositiveNode"); - Array<Real>::const_vector_iterator it = nodes.begin(spatial_dimension); - Array<Real>::const_vector_iterator end = nodes.end(spatial_dimension); + auto it = nodes.begin(spatial_dimension); + auto end = nodes.end(spatial_dimension); UInt index = 0; for (; it != end ; ++it , ++index){ const Vector<Real> & position = *it; if (position(0) > 0) group.add(index); } \end{cpp} \subsection{The \texttt{ElementGroup} object} A group of elements is stored in \code{ElementGroup} objects. Since a group can contain elements of various types the \code{ElementGroup} object stores indexes in a \code{ElementTypeMapArray<UInt>} object. Then elements can be added to the group by calling \code{addElement}. For instance, selecting the elements for which the barycenter of the nodes has a positive $X$ coordinate can be made with: \begin{cpp} ElementGroup & group = mesh.createElementGroup("XpositiveElement"); Mesh::type_iterator it = mesh.firstType(); Mesh::type_iterator end = mesh.lastType(); Vector<Real> barycenter(spatial_dimension); for(; it != end; ++it){ UInt nb_element = mesh.getNbElement(*it); for(UInt e = 0; e < nb_element; ++e) { ElementType type = *it; mesh.getBarycenter(e, type, barycenter.storage()); if (barycenter(0) > 0) group.add(type,e); } } \end{cpp} %%% Local Variables: %%% mode: latex %%% TeX-master: "manual" %%% End: diff --git a/examples/io/dumper/locomotive_tools.cc b/examples/io/dumper/locomotive_tools.cc index 74262dc67..12c5184a0 100644 --- a/examples/io/dumper/locomotive_tools.cc +++ b/examples/io/dumper/locomotive_tools.cc @@ -1,93 +1,93 @@ /** * @file locomotive_tools.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * * @date creation: Mon Aug 17 2015 * @date last modification: Mon Jan 18 2016 * * @brief Common functions for the dumper examples * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include "locomotive_tools.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ void applyRotation(const Vector<Real> & center, Real angle, const Array<Real> & nodes, Array<Real> & displacement, const Array<UInt> & node_group) { - Array<Real>::const_vector_iterator nodes_it = + auto nodes_it = nodes.begin(nodes.getNbComponent()); - Array<Real>::vector_iterator disp_it = displacement.begin(center.size()); + auto disp_it = displacement.begin(center.size()); Array<UInt>::const_scalar_iterator node_num_it = node_group.begin(); Array<UInt>::const_scalar_iterator node_num_end = node_group.end(); Vector<Real> pos_rel(center.size()); for (; node_num_it != node_num_end; ++node_num_it) { const Vector<Real> pos = nodes_it[*node_num_it]; for (UInt i = 0; i < pos.size(); ++i) pos_rel(i) = pos(i); Vector<Real> dis = disp_it[*node_num_it]; pos_rel -= center; Real radius = pos_rel.norm(); if (std::abs(radius) < Math::getTolerance()) continue; Real phi_i = std::acos(pos_rel(_x) / radius); if (pos_rel(_y) < 0) phi_i *= -1; dis(_x) = std::cos(phi_i - angle) * radius - pos_rel(_x); dis(_y) = std::sin(phi_i - angle) * radius - pos_rel(_y); } } /* -------------------------------------------------------------------------- */ void fillColour(const Mesh & mesh, ElementTypeMapArray<UInt> & colour) { const ElementTypeMapArray<std::string> & phys_data = mesh.getData<std::string>("physical_names"); const Array<std::string> & txt_colour = phys_data(_triangle_3); Array<UInt> & id_colour = colour(_triangle_3); for (UInt i = 0; i < txt_colour.size(); ++i) { std::string phy_name = txt_colour(i); if (phy_name == "red") id_colour(i) = 3; else if (phy_name == "white" || phy_name == "lwheel_1" || phy_name == "rwheel_1") id_colour(i) = 2; else id_colour(i) = 1; } } diff --git a/extra_packages/extra-materials/src/material_damage/material_damage_iterative.cc b/extra_packages/extra-materials/src/material_damage/material_damage_iterative.cc index 99f1295b2..76c1e14b8 100644 --- a/extra_packages/extra-materials/src/material_damage/material_damage_iterative.cc +++ b/extra_packages/extra-materials/src/material_damage/material_damage_iterative.cc @@ -1,259 +1,255 @@ /** * @file material_damage_iterative.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * * @brief Specialization of the class material damage to damage only one gauss * point at a time and propagate damage in a linear way. Max principal stress * criterion is used as a failure criterion. * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "material_damage_iterative.hh" -#include "solid_mechanics_model_RVE.hh" #include "communicator.hh" #include "data_accessor.hh" +#include "solid_mechanics_model_RVE.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialDamageIterative<spatial_dimension>::MaterialDamageIterative( SolidMechanicsModel & model, const ID & id) - : MaterialDamage<spatial_dimension>(model, id), - Sc("Sc", *this), reduction_step("damage_step", *this), + : MaterialDamage<spatial_dimension>(model, id), Sc("Sc", *this), + reduction_step("damage_step", *this), equivalent_stress("equivalent_stress", *this), max_reductions(0), norm_max_equivalent_stress(0) { AKANTU_DEBUG_IN(); this->registerParam("Sc", Sc, _pat_parsable, "critical stress threshold"); this->registerParam("prescribed_dam", prescribed_dam, 0.1, _pat_parsable | _pat_modifiable, "prescribed damage"); this->registerParam( "dam_threshold", dam_threshold, 0.8, _pat_parsable | _pat_modifiable, "damage threshold at which damage damage will be set to 1"); this->registerParam( "dam_tolerance", dam_tolerance, 0.01, _pat_parsable | _pat_modifiable, "damage tolerance to decide if quadrature point will be damageed"); this->registerParam("max_damage", max_damage, 0.99999, _pat_parsable | _pat_modifiable, "maximum damage value"); this->registerParam("max_reductions", max_reductions, UInt(10), _pat_parsable | _pat_modifiable, "max reductions"); this->use_previous_stress = true; this->use_previous_gradu = true; this->Sc.initialize(1); this->equivalent_stress.initialize(1); this->reduction_step.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialDamageIterative<spatial_dimension>:: computeNormalizedEquivalentStress(const Array<Real> & grad_u, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// Vector to store eigenvalues of current stress tensor Vector<Real> eigenvalues(spatial_dimension); - Array<Real>::const_iterator<Real> Sc_it = Sc(el_type, ghost_type).begin(); - Array<Real>::iterator<Real> equivalent_stress_it = - equivalent_stress(el_type, ghost_type).begin(); + auto Sc_it = Sc(el_type, ghost_type).begin(); + auto equivalent_stress_it = equivalent_stress(el_type, ghost_type).begin(); Array<Real>::const_matrix_iterator grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); Array<Real>::const_matrix_iterator grad_u_end = grad_u.end(spatial_dimension, spatial_dimension); Real * dam = this->damage(el_type, ghost_type).storage(); Matrix<Real> sigma(spatial_dimension, spatial_dimension); for (; grad_u_it != grad_u_end; ++grad_u_it) { sigma.clear(); MaterialElastic<spatial_dimension>::computeStressOnQuad(*grad_u_it, sigma, 0.); computeDamageAndStressOnQuad(sigma, *dam); /// compute eigenvalues sigma.eig(eigenvalues); /// find max eigenvalue and normalize by tensile strength *equivalent_stress_it = *(std::max_element(eigenvalues.storage(), eigenvalues.storage() + spatial_dimension)) / *(Sc_it); ++Sc_it; ++equivalent_stress_it; ++dam; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialDamageIterative<spatial_dimension>::computeAllStresses( GhostType ghost_type) { AKANTU_DEBUG_IN(); /// reset normalized maximum equivalent stress if (ghost_type == _not_ghost) norm_max_equivalent_stress = 0; MaterialDamage<spatial_dimension>::computeAllStresses(ghost_type); /// find global Gauss point with highest stress - auto rve_model = - dynamic_cast<SolidMechanicsModelRVE *>(&this->model); + auto rve_model = dynamic_cast<SolidMechanicsModelRVE *>(&this->model); if (rve_model == NULL) { /// is no RVE model const auto & comm = this->model.getMesh().getCommunicator(); comm.allReduce(norm_max_equivalent_stress, SynchronizerOperation::_max); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialDamageIterative<spatial_dimension>:: findMaxNormalizedEquivalentStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (ghost_type == _not_ghost) { // const Array<Real> & e_stress = equivalent_stress(el_type); // if (e_stress.begin() != e_stress.end() ) { - // Array<Real>::const_iterator<Real> equivalent_stress_it_max = + // auto equivalent_stress_it_max = // std::max_element(e_stress.begin(),e_stress.end()); // /// check if max equivalent stress for this element type is greater // than the current norm_max_eq_stress // if (*equivalent_stress_it_max > norm_max_equivalent_stress) // norm_max_equivalent_stress = *equivalent_stress_it_max; // } const Array<Real> & e_stress = equivalent_stress(el_type); - Array<Real>::const_iterator<Real> equivalent_stress_it = e_stress.begin(); - Array<Real>::const_iterator<Real> equivalent_stress_end = e_stress.end(); + auto equivalent_stress_it = e_stress.begin(); + auto equivalent_stress_end = e_stress.end(); Array<Real> & dam = this->damage(el_type); - Array<Real>::iterator<Real> dam_it = dam.begin(); + auto dam_it = dam.begin(); for (; equivalent_stress_it != equivalent_stress_end; ++equivalent_stress_it, ++dam_it) { /// check if max equivalent stress for this element type is greater than /// the current norm_max_eq_stress and if the element is not already fully /// damaged if (*equivalent_stress_it > norm_max_equivalent_stress && *dam_it < max_damage) { norm_max_equivalent_stress = *equivalent_stress_it; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialDamageIterative<spatial_dimension>::computeStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialDamage<spatial_dimension>::computeStress(el_type, ghost_type); Real * dam = this->damage(el_type, ghost_type).storage(); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); computeDamageAndStressOnQuad(sigma, *dam); ++dam; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; computeNormalizedEquivalentStress(this->gradu(el_type, ghost_type), el_type, ghost_type); norm_max_equivalent_stress = 0; findMaxNormalizedEquivalentStress(el_type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> UInt MaterialDamageIterative<spatial_dimension>::updateDamage() { UInt nb_damaged_elements = 0; AKANTU_DEBUG_ASSERT(prescribed_dam > 0., "Your prescribed damage must be greater than zero"); if (norm_max_equivalent_stress >= 1.) { AKANTU_DEBUG_IN(); /// update the damage only on non-ghosts elements! Doesn't make sense to /// update on ghost. GhostType ghost_type = _not_ghost; ; Mesh::type_iterator it = this->model.getFEEngine().getMesh().firstType( spatial_dimension, ghost_type); Mesh::type_iterator last_type = this->model.getFEEngine().getMesh().lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { ElementType el_type = *it; const Array<Real> & e_stress = equivalent_stress(el_type); - Array<Real>::const_iterator<Real> equivalent_stress_it = e_stress.begin(); - Array<Real>::const_iterator<Real> equivalent_stress_end = e_stress.end(); + auto equivalent_stress_it = e_stress.begin(); + auto equivalent_stress_end = e_stress.end(); Array<Real> & dam = this->damage(el_type); - Array<Real>::iterator<Real> dam_it = dam.begin(); - Array<UInt>::scalar_iterator reduction_it = - this->reduction_step(el_type, ghost_type).begin(); + auto dam_it = dam.begin(); + auto reduction_it = this->reduction_step(el_type, ghost_type).begin(); for (; equivalent_stress_it != equivalent_stress_end; ++equivalent_stress_it, ++dam_it, ++reduction_it) { /// check if damage occurs if (*equivalent_stress_it >= (1 - dam_tolerance) * norm_max_equivalent_stress) { /// check if this element can still be damaged if (*reduction_it == this->max_reductions) continue; *reduction_it += 1; if (*reduction_it == this->max_reductions) { *dam_it = max_damage; } else { *dam_it += prescribed_dam; } nb_damaged_elements += 1; } } } } - auto * rve_model = - dynamic_cast<SolidMechanicsModelRVE *>(&this->model); + auto * rve_model = dynamic_cast<SolidMechanicsModelRVE *>(&this->model); if (rve_model == NULL) { const auto & comm = this->model.getMesh().getCommunicator(); comm.allReduce(nb_damaged_elements, SynchronizerOperation::_sum); } - + AKANTU_DEBUG_OUT(); return nb_damaged_elements; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialDamageIterative<spatial_dimension>::updateEnergiesAfterDamage( ElementType el_type, GhostType ghost_type) { MaterialDamage<spatial_dimension>::updateEnergies(el_type, ghost_type); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(damage_iterative, MaterialDamageIterative); } // namespace akantu diff --git a/extra_packages/extra-materials/src/material_damage/material_orthotropic_damage_iterative.cc b/extra_packages/extra-materials/src/material_damage/material_orthotropic_damage_iterative.cc index 21b7c819a..aab883b2e 100644 --- a/extra_packages/extra-materials/src/material_damage/material_orthotropic_damage_iterative.cc +++ b/extra_packages/extra-materials/src/material_damage/material_orthotropic_damage_iterative.cc @@ -1,379 +1,379 @@ /** * @file material_damage_iterative.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date Sun Mar 8 12:54:30 2015 * * @brief Specialization of the class material damage to damage only one gauss * point at a time and propagate damage in a linear way. Max principal stress * criterion is used as a failure criterion. * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "material_orthotropic_damage_iterative.hh" #include "communicator.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialOrthotropicDamageIterative<spatial_dimension>:: MaterialOrthotropicDamageIterative(SolidMechanicsModel & model, const ID & id) : MaterialOrthotropicDamage<spatial_dimension>(model, id), Sc("Sc", *this), equivalent_stress("equivalent_stress", *this), stress_dir("equiv_stress_dir", *this), norm_max_equivalent_stress(0) { AKANTU_DEBUG_IN(); this->registerParam("Sc", Sc, _pat_parsable, "critical stress threshold"); this->registerParam("prescribed_dam", prescribed_dam, 0.1, _pat_parsable | _pat_modifiable, "increase of damage in every step"); this->registerParam( "dam_threshold", dam_threshold, 0.8, _pat_parsable | _pat_modifiable, "damage threshold at which damage damage will be set to 1"); this->use_previous_stress = true; this->use_previous_gradu = true; this->Sc.initialize(1); this->equivalent_stress.initialize(1); this->stress_dir.initialize(spatial_dimension * spatial_dimension); /// the Gauss point with the highest stress can only be of type _not_ghost q_max.ghost_type = _not_ghost; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialOrthotropicDamageIterative<spatial_dimension>:: computeNormalizedEquivalentStress(const Array<Real> & grad_u, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// Vector to store eigenvalues of current stress tensor Vector<Real> eigenvalues(spatial_dimension); - Array<Real>::const_iterator<Real> Sc_it = Sc(el_type).begin(); - Array<Real>::iterator<Real> equivalent_stress_it = + auto Sc_it = Sc(el_type).begin(); + auto equivalent_stress_it = equivalent_stress(el_type).begin(); Array<Real>::const_matrix_iterator grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); Array<Real>::const_matrix_iterator grad_u_end = grad_u.end(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator stress_dir_it = this->stress_dir(el_type).begin(spatial_dimension, spatial_dimension); /// initialize matrix to store the stress for the criterion (only different in /// non-local) Matrix<Real> sigma(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator damage_iterator = this->damage(el_type, ghost_type) .begin(this->spatial_dimension, this->spatial_dimension); Array<Real>::matrix_iterator damage_dir_it = this->damage_dir_vecs(el_type, ghost_type) .begin(this->spatial_dimension, this->spatial_dimension); /// for the computation of the Cauchy stress the matrices (1-D) and /// (1-D)^(1/2) are needed. For the formulation see Engineering /// Damage Mechanics by Lemaitre and Desmorat. Matrix<Real> one_minus_D(this->spatial_dimension, this->spatial_dimension); Matrix<Real> sqrt_one_minus_D(this->spatial_dimension, this->spatial_dimension); Matrix<Real> one_minus_D_rotated(this->spatial_dimension, this->spatial_dimension); Matrix<Real> sqrt_one_minus_D_rotated(this->spatial_dimension, this->spatial_dimension); Matrix<Real> rotation_tmp(this->spatial_dimension, this->spatial_dimension); /// create matrix to store the first term of the computation of the /// Cauchy stress Matrix<Real> first_term(this->spatial_dimension, this->spatial_dimension); Matrix<Real> third_term(this->spatial_dimension, this->spatial_dimension); for (; grad_u_it != grad_u_end; ++Sc_it, ++equivalent_stress_it, ++stress_dir_it, ++grad_u_it) { sigma.clear(); MaterialOrthotropicDamage<spatial_dimension>::computeStressOnQuad( *grad_u_it, sigma, 0.); /// rotate the tensors from the damage principal coordinate system to the CS /// of the computation if (!(Math::are_float_equal((*damage_iterator).trace(), 0))) { /// compute (1-D) and (1-D)^1/2 this->computeOneMinusD(one_minus_D, *damage_iterator); this->computeSqrtOneMinusD(one_minus_D, sqrt_one_minus_D); this->rotateIntoComputationFrame(one_minus_D, one_minus_D_rotated, *damage_dir_it, rotation_tmp); this->rotateIntoComputationFrame(sqrt_one_minus_D, sqrt_one_minus_D_rotated, *damage_dir_it, rotation_tmp); } else { this->computeOneMinusD(one_minus_D_rotated, *damage_iterator); this->computeSqrtOneMinusD(one_minus_D_rotated, sqrt_one_minus_D_rotated); } computeDamageAndStressOnQuad(sigma, one_minus_D_rotated, sqrt_one_minus_D_rotated, *damage_iterator, first_term, third_term); /// compute the maximum principal stresses and their directions sigma.eig(eigenvalues, *stress_dir_it); *equivalent_stress_it = eigenvalues(0) / *(Sc_it); ++damage_dir_it; ++damage_iterator; } // for(;sigma_it != sigma_end; ++sigma_it, // ++Sc_it, ++equivalent_stress_it, ++stress_dir_it) { // /// compute the maximum principal stresses and their directions // (*sigma_it).eig(eigenvalues, *stress_dir_it); // *equivalent_stress_it = eigenvalues(0) / *(Sc_it); // } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialOrthotropicDamageIterative<spatial_dimension>::computeAllStresses( GhostType ghost_type) { AKANTU_DEBUG_IN(); /// reset normalized maximum equivalent stress if (ghost_type == _not_ghost) norm_max_equivalent_stress = 0; MaterialOrthotropicDamage<spatial_dimension>::computeAllStresses(ghost_type); /// find global Gauss point with highest stress this->model.getMesh().getCommunicator().allReduce( norm_max_equivalent_stress, SynchronizerOperation::_max); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialOrthotropicDamageIterative<spatial_dimension>:: findMaxNormalizedEquivalentStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (ghost_type == _not_ghost) { /// initialize the iterators for the equivalent stress and the damage const Array<Real> & e_stress = equivalent_stress(el_type); auto equivalent_stress_it = e_stress.begin(); auto equivalent_stress_end = e_stress.end(); Array<Real> & dam = this->damage(el_type); auto dam_it = dam.begin(this->spatial_dimension, this->spatial_dimension); auto damage_directions_it = this->damage_dir_vecs(el_type, _not_ghost) .begin(this->spatial_dimension, this->spatial_dimension); auto stress_dir_it = this->stress_dir(el_type, _not_ghost) .begin(spatial_dimension, spatial_dimension); /// initialize the matrices for damage rotation results Matrix<Real> tmp(spatial_dimension, spatial_dimension); Matrix<Real> dam_in_computation_frame(spatial_dimension, spatial_dimension); Matrix<Real> dam_in_stress_frame(spatial_dimension, spatial_dimension); for (; equivalent_stress_it != equivalent_stress_end; ++equivalent_stress_it, ++dam_it, ++damage_directions_it, ++stress_dir_it) { /// check if max equivalent stress for this element type is greater than /// the current norm_max_eq_stress if (*equivalent_stress_it > norm_max_equivalent_stress && (spatial_dimension * this->max_damage - (*dam_it).trace() > Math::getTolerance())) { if (Math::are_float_equal((*dam_it).trace(), 0)) { /// gauss point has not been damaged yet norm_max_equivalent_stress = *equivalent_stress_it; q_max.type = el_type; q_max.global_num = equivalent_stress_it - e_stress.begin(); } else { /// find the damage increment on this Gauss point /// rotate damage into stress frame this->rotateIntoComputationFrame(*dam_it, dam_in_computation_frame, *damage_directions_it, tmp); this->rotateIntoNewFrame(dam_in_computation_frame, dam_in_stress_frame, *stress_dir_it, tmp); /// add damage increment dam_in_stress_frame(0, 0) += prescribed_dam; /// find new principal directions of damage Vector<Real> dam_eigenvalues(spatial_dimension); dam_in_stress_frame.eig(dam_eigenvalues); bool limit_reached = false; for (UInt i = 0; i < spatial_dimension; ++i) { if (dam_eigenvalues(i) + Math::getTolerance() > this->max_damage) limit_reached = true; } if (!limit_reached) { norm_max_equivalent_stress = *equivalent_stress_it; q_max.type = el_type; q_max.global_num = equivalent_stress_it - e_stress.begin(); } } } /// end if equiv_stress > max_equiv_stress } /// end loop over all gauss points of this element type } // end if(_not_ghost) AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialOrthotropicDamageIterative<spatial_dimension>::computeStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialOrthotropicDamage<spatial_dimension>::computeStress(el_type, ghost_type); auto damage_iterator = this->damage(el_type, ghost_type) .begin(this->spatial_dimension, this->spatial_dimension); auto damage_dir_it = this->damage_dir_vecs(el_type, ghost_type) .begin(this->spatial_dimension, this->spatial_dimension); /// for the computation of the Cauchy stress the matrices (1-D) and /// (1-D)^(1/2) are needed. For the formulation see Engineering /// Damage Mechanics by Lemaitre and Desmorat. Matrix<Real> one_minus_D(this->spatial_dimension, this->spatial_dimension); Matrix<Real> sqrt_one_minus_D(this->spatial_dimension, this->spatial_dimension); Matrix<Real> one_minus_D_rotated(this->spatial_dimension, this->spatial_dimension); Matrix<Real> sqrt_one_minus_D_rotated(this->spatial_dimension, this->spatial_dimension); Matrix<Real> rotation_tmp(this->spatial_dimension, this->spatial_dimension); /// create matrix to store the first term of the computation of the /// Cauchy stress Matrix<Real> first_term(this->spatial_dimension, this->spatial_dimension); Matrix<Real> third_term(this->spatial_dimension, this->spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); /// rotate the tensors from the damage principal coordinate system to the CS /// of the computation if (!(Math::are_float_equal((*damage_iterator).trace(), 0))) { /// compute (1-D) and (1-D)^1/2 this->computeOneMinusD(one_minus_D, *damage_iterator); this->computeSqrtOneMinusD(one_minus_D, sqrt_one_minus_D); this->rotateIntoComputationFrame(one_minus_D, one_minus_D_rotated, *damage_dir_it, rotation_tmp); this->rotateIntoComputationFrame(sqrt_one_minus_D, sqrt_one_minus_D_rotated, *damage_dir_it, rotation_tmp); } else { this->computeOneMinusD(one_minus_D_rotated, *damage_iterator); this->computeSqrtOneMinusD(one_minus_D_rotated, sqrt_one_minus_D_rotated); } computeDamageAndStressOnQuad(sigma, one_minus_D_rotated, sqrt_one_minus_D_rotated, *damage_iterator, first_term, third_term); ++damage_dir_it; ++damage_iterator; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; computeNormalizedEquivalentStress(this->gradu(el_type, ghost_type), el_type, ghost_type); norm_max_equivalent_stress = 0; findMaxNormalizedEquivalentStress(el_type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> UInt MaterialOrthotropicDamageIterative<spatial_dimension>::updateDamage() { UInt nb_damaged_elements = 0; AKANTU_DEBUG_ASSERT(prescribed_dam > 0., "Your prescribed damage must be greater than zero"); if (norm_max_equivalent_stress >= 1.) { AKANTU_DEBUG_IN(); /// get the arrays and iterators for the element_type of the highest /// quadrature point ElementType el_type = q_max.type; UInt q_global_num = q_max.global_num; Array<Real> & dam = this->damage(el_type, _not_ghost); auto dam_it = dam.begin(this->spatial_dimension, this->spatial_dimension); auto damage_directions_it = this->damage_dir_vecs(el_type, _not_ghost) .begin(this->spatial_dimension, this->spatial_dimension); auto stress_dir_it = this->stress_dir(el_type, _not_ghost) .begin(spatial_dimension, spatial_dimension); /// initialize the matrices for damage rotation results Matrix<Real> tmp(spatial_dimension, spatial_dimension); Matrix<Real> dam_in_computation_frame(spatial_dimension, spatial_dimension); Matrix<Real> dam_in_stress_frame(spatial_dimension, spatial_dimension); /// references to damage and directions of highest Gauss point Matrix<Real> q_dam = dam_it[q_global_num]; Matrix<Real> q_dam_dir = damage_directions_it[q_global_num]; Matrix<Real> q_stress_dir = stress_dir_it[q_global_num]; /// increment damage /// find the damage increment on this Gauss point /// rotate damage into stress frame this->rotateIntoComputationFrame(q_dam, dam_in_computation_frame, q_dam_dir, tmp); this->rotateIntoNewFrame(dam_in_computation_frame, dam_in_stress_frame, q_stress_dir, tmp); /// add damage increment dam_in_stress_frame(0, 0) += prescribed_dam; /// find new principal directions of damage Vector<Real> dam_eigenvalues(spatial_dimension); dam_in_stress_frame.eig(dam_eigenvalues, q_dam_dir); for (UInt i = 0; i < spatial_dimension; ++i) { q_dam(i, i) = dam_eigenvalues(i); if (q_dam(i, i) + Math::getTolerance() >= dam_threshold) q_dam(i, i) = this->max_damage; } nb_damaged_elements += 1; } this->model.getMesh().getCommunicator().allReduce( nb_damaged_elements, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return nb_damaged_elements; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialOrthotropicDamageIterative< spatial_dimension>::updateEnergiesAfterDamage(ElementType el_type, GhostType ghost_type) { MaterialOrthotropicDamage<spatial_dimension>::updateEnergies(el_type, ghost_type); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(orthotropic_damage_iterative, MaterialOrthotropicDamageIterative); } // namespace akantu diff --git a/extra_packages/extra-materials/test/test_material_damage/test_material_damage_iterative_non_local_serial.cc b/extra_packages/extra-materials/test/test_material_damage/test_material_damage_iterative_non_local_serial.cc index 51b1ed6bc..be7949b0c 100644 --- a/extra_packages/extra-materials/test/test_material_damage/test_material_damage_iterative_non_local_serial.cc +++ b/extra_packages/extra-materials/test/test_material_damage/test_material_damage_iterative_non_local_serial.cc @@ -1,224 +1,224 @@ /** * @file test_material_damage_iterative_non_local_serial.cc * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Thu Nov 26 12:20:15 2015 * * @brief test the material damage iterative non local in serial * * @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_iterative_non_local.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { Math::setTolerance(1e-13); debug::setDebugLevel(dblWarning); initialize("material_non_local.dat" ,argc, argv); const UInt spatial_dimension = 2; ElementType element_type = _triangle_3; /// read the mesh and partion it Mesh mesh(spatial_dimension); mesh.read("plate.msh"); /// model creation SolidMechanicsModel model(mesh); /// initialization of the model model.initFull(SolidMechanicsModelOptions(_static)); /// boundary conditions /// Dirichlet BC mesh.createGroupsFromMeshData<std::string>("physical_names"); // creates groups from mesh names model.applyBC(BC::Dirichlet::FixedValue(0, _x), "left"); model.applyBC(BC::Dirichlet::FixedValue(0, _y), "bottom"); model.applyBC(BC::Dirichlet::FixedValue(2., _y), "top"); /// add fields that should be dumped model.setBaseName("material_damage_iterative_test"); model.addDumpFieldVector("displacement");; model.addDumpField("stress"); model.addDumpField("blocked_dofs"); model.addDumpField("residual"); model.addDumpField("grad_u"); model.addDumpField("grad_u non local"); model.addDumpField("damage"); model.addDumpField("partitions"); model.addDumpField("material_index"); model.addDumpField("Sc"); model.addDumpField("force"); model.addDumpField("equivalent_stress"); model.dump(); MaterialDamageIterativeNonLocal<spatial_dimension> & material = dynamic_cast<MaterialDamageIterativeNonLocal<spatial_dimension> & >(model.getMaterial(0)); Real error; bool converged = false; Real max_eq_stress = 0; /// solve the system converged = model.solveStep<_scm_newton_raphson_tangent_modified, _scc_increment>(1e-4, error, 2); if (converged == false) { std::cout << "The error is: " << error << std::endl; AKANTU_DEBUG_ASSERT(converged, "Did not converge"); } model.dump(); /// check the non-local grad_u: since grad_u is constant everywhere /// also the grad_u non-local has to be constant Array<Real> & grad_u_nl = material.getInternal<Real>("grad_u non local")(element_type, _not_ghost); Array<Real>::const_matrix_iterator grad_u_nl_it = grad_u_nl.begin(spatial_dimension,spatial_dimension); Array<Real>::const_matrix_iterator grad_u_nl_end = grad_u_nl.end(spatial_dimension,spatial_dimension); Real diff = 0.; Matrix<Real> diff_matrix(spatial_dimension, spatial_dimension); Matrix<Real> const_grad_u(spatial_dimension, spatial_dimension, 0.); const_grad_u(1,1) = 1.; for (; grad_u_nl_it != grad_u_nl_end; ++grad_u_nl_it) { diff_matrix = (*grad_u_nl_it) - const_grad_u; diff += diff_matrix.norm<L_2>(); } if (diff > 10.e-13) { std::cout << "Error in the non-local grad_u computation" << std::endl; return EXIT_FAILURE; } /// change the displacement in one node to modify grad_u Array<Real> & displ = model.getDisplacement(); displ(0,1) = 2.6; /// compute stresses: this will average grad_u and compute the max. eq. stress model.updateResidual(); model.dump(); /// due to the change in the displacement element 33 and 37 will /// have a grad_u different then one const Array<Real> & grad_u = material.getInternal<Real>("grad_u")(element_type, _not_ghost); Array<Real>::const_matrix_iterator grad_u_it = grad_u.begin(spatial_dimension,spatial_dimension); Array<Real>::const_matrix_iterator grad_u_end = grad_u.end(spatial_dimension,spatial_dimension); diff = 0.; diff_matrix.clear(); UInt counter = 0; for (; grad_u_it != grad_u_end; ++grad_u_it) { diff_matrix = (*grad_u_it) - const_grad_u; if (counter == 34 || counter == 38) { if ((diff_matrix.norm<L_2>()) < 0.1) { std::cout << "Error in the grad_u computation" << std::endl; return EXIT_FAILURE; } } else diff += diff_matrix.norm<L_2>(); ++counter; } if (diff > 10.e-13) { std::cout << "Error in the grad_u computation" << std::endl; return EXIT_FAILURE; } /// check that the non-local grad_u diff = 0.; diff_matrix.clear(); Real nl_radius = 1.0; /// same values as in material file grad_u_nl_it = grad_u_nl.begin(spatial_dimension,spatial_dimension); ElementTypeMapReal quad_coords("quad_coords"); mesh.initElementTypeMapArray(quad_coords, spatial_dimension, spatial_dimension, false, _ek_regular, true); model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); UInt nb_elements = mesh.getNbElement(element_type, _not_ghost); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(element_type); Array<Real> & coords = quad_coords(element_type, _not_ghost); - Array<Real>::const_vector_iterator coord_it = coords.begin(spatial_dimension); + auto coord_it = coords.begin(spatial_dimension); Vector<Real> q1(spatial_dimension); Vector<Real> q2(spatial_dimension); q1 = coord_it[34]; q2 = coord_it[38]; for (UInt e = 0; e < nb_elements; ++e) { for (UInt q = 0; q < nb_quads; ++q, ++coord_it, ++grad_u_nl_it) { diff_matrix = (*grad_u_nl_it) - const_grad_u; if ((q1.distance(*coord_it) <= (nl_radius + Math::getTolerance())) || (q2.distance(*coord_it) <= (nl_radius + Math::getTolerance()))) { if ((diff_matrix.norm<L_2>()) < 1.e-6) { std::cout << (diff_matrix.norm<L_2>()) << std::endl; std::cout << "Error in the non-local grad_u computation" << std::endl; return EXIT_FAILURE; } } else diff += diff_matrix.norm<L_2>(); } } if (diff > 10.e-13) { std::cout << "Error in the non-local grad_u computation" << std::endl; return EXIT_FAILURE; } /// make sure that the normalized equivalent stress is based on the /// non-local grad_u for this test check the elements that have the /// constant stress of 1 but different non-local gradu because they /// are in the neighborhood of the modified elements coord_it = coords.begin(spatial_dimension); const Array<Real> & eq_stress = material.getInternal<Real>("equivalent_stress")(element_type, _not_ghost); Array<Real>::const_scalar_iterator eq_stress_it = eq_stress.begin(); counter = 0; for (UInt e = 0; e < nb_elements; ++e) { for (UInt q = 0; q < nb_quads; ++q, ++coord_it, ++grad_u_nl_it, ++eq_stress_it) { if (counter == 34 || counter == 38) continue; if (((q1.distance(*coord_it) <= (nl_radius + Math::getTolerance())) || (q2.distance(*coord_it) <= (nl_radius + Math::getTolerance()))) && Math::are_float_equal(*eq_stress_it, 0.1)) { std::cout << "the normalized equivalent stress is most likely based on the local, not the non-local grad_u!!!!" << std::endl; finalize(); return EXIT_FAILURE; } ++counter; } } max_eq_stress = material.getNormMaxEquivalentStress(); if (!Math::are_float_equal(max_eq_stress, 0.1311267235941873)){ std::cout << "the maximum equivalent stress is wrong" << std::endl; finalize(); return EXIT_FAILURE; } model.dump(); finalize(); return EXIT_SUCCESS; } diff --git a/extra_packages/traction-at-split-node-contact/src/ntn_contact/mIIasym_contact.cc b/extra_packages/traction-at-split-node-contact/src/ntn_contact/mIIasym_contact.cc index 625b45da2..bebc0675e 100644 --- a/extra_packages/traction-at-split-node-contact/src/ntn_contact/mIIasym_contact.cc +++ b/extra_packages/traction-at-split-node-contact/src/ntn_contact/mIIasym_contact.cc @@ -1,108 +1,108 @@ /** * @file mIIasym_contact.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * * * @brief * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ // simtools #include "mIIasym_contact.hh" namespace akantu { /* -------------------------------------------------------------------------- */ MIIASYMContact::MIIASYMContact(SolidMechanicsModel & model, const ContactID & id, const MemoryID & memory_id) : NTRFContact(model,id,memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MIIASYMContact::updateImpedance() { AKANTU_DEBUG_IN(); NTRFContact::updateImpedance(); for (UInt i=0; i<this->impedance.getSize(); ++i) { this->impedance(i) *= 0.5; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// WARNING: this is only valid for the acceleration in equilibrium void MIIASYMContact::computeRelativeNormalField(const Array<Real> & field, Array<Real> & rel_normal_field) const { AKANTU_DEBUG_IN(); NTRFContact::computeRelativeNormalField(field, rel_normal_field); - for (Array<Real>::iterator<Real> it_rtfield = rel_normal_field.begin(); + for (auto it_rtfield = rel_normal_field.begin(); it_rtfield != rel_normal_field.end(); ++it_rtfield) { // in the anti-symmetric case *it_rtfield *= 2.; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MIIASYMContact::computeRelativeTangentialField(const Array<Real> & field, Array<Real> & rel_tang_field) const { AKANTU_DEBUG_IN(); NTRFContact::computeRelativeTangentialField(field, rel_tang_field); UInt dim = this->model.getSpatialDimension(); for (Array<Real>::iterator< Vector<Real> > it_rtfield = rel_tang_field.begin(dim); it_rtfield != rel_tang_field.end(dim); ++it_rtfield) { // in the anti-symmetric case, the tangential fields become twice as large *it_rtfield *= 2.; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MIIASYMContact::computeContactPressureInEquilibrium() { AKANTU_DEBUG_IN(); NTRFContact::computeContactPressure(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MIIASYMContact::printself(std::ostream & stream, int indent) const { AKANTU_DEBUG_IN(); std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "MIIASYMContact [" << std::endl; NTRFContact::printself(stream,indent); stream << space << "]" << std::endl; AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_friction.cc b/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_friction.cc index 72cae3346..2d7516a25 100644 --- a/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_friction.cc +++ b/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_friction.cc @@ -1,374 +1,374 @@ /** * @file ntn_base_friction.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * * * @brief implementation of ntn base friction * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ // simtools #include "ntn_base_friction.hh" #include "dumper_text.hh" #include "dumper_nodal_field.hh" namespace akantu { /* -------------------------------------------------------------------------- */ NTNBaseFriction::NTNBaseFriction(NTNBaseContact * contact, const FrictionID & id, const MemoryID & memory_id) : Memory(id,memory_id), Parsable(_st_friction, id), Dumpable(), contact(contact), is_sticking(0,1,true,id+":is_sticking",true,"is_sticking"), frictional_strength(0,1,0.,id+":frictional_strength",0.,"frictional_strength"), friction_traction(0,contact->getModel().getSpatialDimension(), 0.,id+":friction_traction",0.,"friction_traction"), slip(0,1,0.,id+":slip",0.,"slip"), cumulative_slip(0,1,0.,id+":cumulative_slip",0.,"cumulative_slip"), slip_velocity(0,contact->getModel().getSpatialDimension(), 0.,id+":slip_velocity",0.,"slip_velocity") { AKANTU_DEBUG_IN(); this->contact->registerSynchronizedArray(this->is_sticking); this->contact->registerSynchronizedArray(this->frictional_strength); this->contact->registerSynchronizedArray(this->friction_traction); this->contact->registerSynchronizedArray(this->slip); this->contact->registerSynchronizedArray(this->cumulative_slip); this->contact->registerSynchronizedArray(this->slip_velocity); contact->getModel().setIncrementFlagOn(); this->registerExternalDumper(contact->getDumper(), contact->getDefaultDumperName(), true); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::updateSlip() { AKANTU_DEBUG_IN(); SolidMechanicsModel & model = this->contact->getModel(); UInt dim = model.getSpatialDimension(); // synchronize increment this->contact->getSynchronizerRegistry()->synchronize(_gst_cf_incr); Array<Real> rel_tan_incr(0,dim); this->contact->computeRelativeTangentialField(model.getIncrement(), rel_tan_incr); Array<Real>::const_iterator< Vector<Real> > it = rel_tan_incr.begin(dim); UInt nb_nodes = this->contact->getNbContactNodes(); for (UInt n=0; n<nb_nodes; ++n) { if (this->is_sticking(n)) { this->slip(n) = 0.; } else { const Vector<Real> & rti = it[n]; this->slip(n) += rti.norm(); this->cumulative_slip(n) += rti.norm(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::computeFrictionTraction() { AKANTU_DEBUG_IN(); this->computeStickTraction(); this->computeFrictionalStrength(); SolidMechanicsModel & model = this->contact->getModel(); UInt dim = model.getSpatialDimension(); // get contact arrays const SynchronizedArray<bool> & is_in_contact = this->contact->getIsInContact(); Array<Real> & traction = const_cast< Array<Real> & >(this->friction_traction.getArray()); Array<Real>::iterator< Vector<Real> > it_fric_trac = traction.begin(dim); this->is_sticking.clear(); // set to not sticking UInt nb_contact_nodes = this->contact->getNbContactNodes(); for (UInt n=0; n<nb_contact_nodes; ++n) { // node pair is in contact if (is_in_contact(n)) { Vector<Real> fric_trac = it_fric_trac[n]; // check if it is larger than frictional strength Real abs_fric = fric_trac.norm(); if (abs_fric != 0.) { Real alpha = this->frictional_strength(n) / abs_fric; // larger -> sliding if (alpha < 1.) { fric_trac *= alpha; } else this->is_sticking(n) = true; } else { // frictional traction is already zero this->is_sticking(n) = true; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::computeStickTraction() { AKANTU_DEBUG_IN(); SolidMechanicsModel & model = this->contact->getModel(); UInt dim = model.getSpatialDimension(); Real delta_t = model.getTimeStep(); UInt nb_contact_nodes = this->contact->getNbContactNodes(); // get contact arrays const SynchronizedArray<Real> & impedance = this->contact->getImpedance(); const SynchronizedArray<bool> & is_in_contact = this->contact->getIsInContact(); // pre-compute the acceleration // (not increment acceleration, because residual is still Kf) Array<Real> acceleration(model.getFEEngine().getMesh().getNbNodes(), dim, 0.); model.solveLumped(acceleration, model.getMass(), model.getResidual(), model.getBlockedDOFs(), model.getF_M2A()); // compute relative normal fields of velocity and acceleration Array<Real> r_velo(0,dim); Array<Real> r_acce(0,dim); Array<Real> r_old_acce(0,dim); this->contact->computeRelativeTangentialField(model.getVelocity(), r_velo); this->contact->computeRelativeTangentialField(acceleration, r_acce); this->contact->computeRelativeTangentialField(model.getAcceleration(), r_old_acce); AKANTU_DEBUG_ASSERT(r_velo.getSize() == nb_contact_nodes, "computeRelativeNormalField does not give back arrays " << "size == nb_contact_nodes. nb_contact_nodes = " << nb_contact_nodes << " | array size = " << r_velo.getSize()); // compute tangential gap_dot array for all nodes Array<Real> gap_dot(nb_contact_nodes, dim); Real * gap_dot_p = gap_dot.storage(); Real * r_velo_p = r_velo.storage(); Real * r_acce_p = r_acce.storage(); Real * r_old_acce_p = r_old_acce.storage(); for (UInt i=0; i<nb_contact_nodes*dim; ++i) { *gap_dot_p = *r_velo_p + delta_t * *r_acce_p - 0.5 * delta_t * *r_old_acce_p; // increment pointers gap_dot_p++; r_velo_p++; r_acce_p++; r_old_acce_p++; } // compute friction traction to stop sliding Array<Real> & traction = const_cast< Array<Real> & >(this->friction_traction.getArray()); - Array<Real>::vector_iterator it_fric_trac = traction.begin(dim); + auto it_fric_trac = traction.begin(dim); for (UInt n=0; n<nb_contact_nodes; ++n) { Vector<Real> fric_trac = it_fric_trac[n]; // node pair is NOT in contact if (!is_in_contact(n)) { fric_trac.clear(); // set to zero } // node pair is in contact else { // compute friction traction for (UInt d=0; d<dim; ++d) fric_trac(d) = impedance(n) * gap_dot(n,d) / 2.; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::applyFrictionTraction() { AKANTU_DEBUG_IN(); SolidMechanicsModel & model = this->contact->getModel(); Array<Real> & residual = model.getResidual(); UInt dim = model.getSpatialDimension(); const SynchronizedArray<UInt> & slaves = this->contact->getSlaves(); const SynchronizedArray<Real> & lumped_boundary_slaves = this->contact->getLumpedBoundarySlaves(); UInt nb_contact_nodes = this->contact->getNbContactNodes(); for (UInt n=0; n<nb_contact_nodes; ++n) { UInt slave = slaves(n); for (UInt d=0; d<dim; ++d) { residual(slave, d) -= lumped_boundary_slaves(n) * this->friction_traction(n,d); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::registerSynchronizedArray(SynchronizedArrayBase & array) { AKANTU_DEBUG_IN(); this->frictional_strength.registerDependingArray(array); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::dumpRestart(const std::string & file_name) const { AKANTU_DEBUG_IN(); this->is_sticking.dumpRestartFile(file_name); this->frictional_strength.dumpRestartFile(file_name); this->friction_traction.dumpRestartFile(file_name); this->slip.dumpRestartFile(file_name); this->cumulative_slip.dumpRestartFile(file_name); this->slip_velocity.dumpRestartFile(file_name); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::readRestart(const std::string & file_name) { AKANTU_DEBUG_IN(); this->is_sticking.readRestartFile(file_name); this->frictional_strength.readRestartFile(file_name); this->friction_traction.readRestartFile(file_name); this->cumulative_slip.readRestartFile(file_name); this->slip_velocity.readRestartFile(file_name); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::setParam(const std::string & name, UInt node, Real value) { AKANTU_DEBUG_IN(); SynchronizedArray<Real> & array = this->get< SynchronizedArray<Real> >(name); Int index = this->contact->getNodeIndex(node); if (index < 0) { AKANTU_DEBUG_WARNING("Node " << node << " is not a contact node. " << "Therefore, cannot set interface parameter!!"); } else { array(index) = value; // put value } AKANTU_DEBUG_OUT(); }; /* -------------------------------------------------------------------------- */ UInt NTNBaseFriction::getNbStickingNodes() const { AKANTU_DEBUG_IN(); UInt nb_stick = 0; UInt nb_nodes = this->contact->getNbContactNodes(); const SynchronizedArray<UInt> & nodes = this->contact->getSlaves(); const SynchronizedArray<bool> & is_in_contact = this->contact->getIsInContact(); const Mesh & mesh = this->contact->getModel().getMesh(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(nodes(n)); bool is_pbc_slave_node = this->contact->getModel().isPBCSlaveNode(nodes(n)); if (is_local_node && !is_pbc_slave_node && is_in_contact(n) && this->is_sticking(n)) { nb_stick++; } } StaticCommunicator::getStaticCommunicator().allReduce(&nb_stick, 1, _so_sum); AKANTU_DEBUG_OUT(); return nb_stick; } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::printself(std::ostream & stream, int indent) const { AKANTU_DEBUG_IN(); std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "NTNBaseFriction [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseFriction::addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { AKANTU_DEBUG_IN(); #ifdef AKANTU_USE_IOHELPER // const SynchronizedArray<UInt> * nodal_filter = &(this->contact->getSlaves()); if(field_id == "is_sticking") { this->internalAddDumpFieldToDumper(dumper_name, field_id, new dumper::NodalField<bool>(this->is_sticking.getArray())); } else if(field_id == "frictional_strength") { this->internalAddDumpFieldToDumper(dumper_name, field_id, new dumper::NodalField<Real>(this->frictional_strength.getArray())); } else if(field_id == "friction_traction") { this->internalAddDumpFieldToDumper(dumper_name, field_id, new dumper::NodalField<Real>(this->friction_traction.getArray())); } else if(field_id == "slip") { this->internalAddDumpFieldToDumper(dumper_name, field_id, new dumper::NodalField<Real>(this->slip.getArray())); } else if(field_id == "cumulative_slip") { this->internalAddDumpFieldToDumper(dumper_name, field_id, new dumper::NodalField<Real>(this->cumulative_slip.getArray())); } else if(field_id == "slip_velocity") { this->internalAddDumpFieldToDumper(dumper_name, field_id, new dumper::NodalField<Real>(this->slip_velocity.getArray())); } else { this->contact->addDumpFieldToDumper(dumper_name, field_id); } #endif AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_contact.cc b/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_contact.cc index 157f31290..935b7f5fe 100644 --- a/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_contact.cc +++ b/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_contact.cc @@ -1,564 +1,564 @@ /** * @file ntn_contact.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * * * @brief implementation of ntn_contact * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ // simtools #include "ntn_contact.hh" #include "dumper_text.hh" #include "dumper_nodal_field.hh" namespace akantu { /* -------------------------------------------------------------------------- */ NTNContact::NTNContact(SolidMechanicsModel & model, const ContactID & id, const MemoryID & memory_id) : NTNBaseContact(model,id,memory_id), masters(0,1,0,id+":masters",std::numeric_limits<UInt>::quiet_NaN(),"masters"), lumped_boundary_masters(0,1,0,id+":lumped_boundary_masters", std::numeric_limits<Real>::quiet_NaN(),"lumped_boundary_masters"), master_elements("master_elements", id, memory_id) { AKANTU_DEBUG_IN(); const Mesh & mesh = this->model.getMesh(); UInt spatial_dimension = this->model.getSpatialDimension(); mesh.initElementTypeMapArray(this->master_elements, 1, spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::pairInterfaceNodes(const ElementGroup & slave_boundary, const ElementGroup & master_boundary, UInt surface_normal_dir, const Mesh & mesh, Array<UInt> & pairs) { AKANTU_DEBUG_IN(); pairs.resize(0); AKANTU_DEBUG_ASSERT(pairs.getNbComponent() == 2, "Array of node pairs should have nb_component = 2," << " but has nb_component = " << pairs.getNbComponent()); UInt dim = mesh.getSpatialDimension(); AKANTU_DEBUG_ASSERT(surface_normal_dir < dim, "Mesh is of " << dim << " dimensions" << " and cannot have direction " << surface_normal_dir << " for surface normal"); // offset for projection computation UInt offset[dim-1]; for (UInt i=0, j=0; i<dim; ++i) { if (surface_normal_dir != i) { offset[j] = i; ++j; } } // find projected node coordinates const Array<Real> & coordinates = mesh.getNodes(); // find slave nodes Array<Real> proj_slave_coord(slave_boundary.getNbNodes(),dim-1,0.); Array<UInt> slave_nodes(slave_boundary.getNbNodes()); UInt n(0); for(ElementGroup::const_node_iterator nodes_it(slave_boundary.node_begin()); nodes_it!= slave_boundary.node_end(); ++nodes_it) { for (UInt d=0; d<dim-1; ++d) { proj_slave_coord(n,d) = coordinates(*nodes_it,offset[d]); slave_nodes(n)=*nodes_it; } ++n; } // find master nodes Array<Real> proj_master_coord(master_boundary.getNbNodes(),dim-1,0.); Array<UInt> master_nodes(master_boundary.getNbNodes()); n=0; for(ElementGroup::const_node_iterator nodes_it(master_boundary.node_begin()); nodes_it!= master_boundary.node_end(); ++nodes_it) { for (UInt d=0; d<dim-1; ++d) { proj_master_coord(n,d) = coordinates(*nodes_it,offset[d]); master_nodes(n)=*nodes_it; } ++n; } // find minimum distance between slave nodes to define tolerance Real min_dist = std::numeric_limits<Real>::max(); for (UInt i=0; i<proj_slave_coord.getSize(); ++i) { for (UInt j=i+1; j<proj_slave_coord.getSize(); ++j) { Real dist = 0.; for (UInt d=0; d<dim-1; ++d) { dist += (proj_slave_coord(i,d) - proj_slave_coord(j,d)) * (proj_slave_coord(i,d) - proj_slave_coord(j,d)); } if (dist < min_dist) { min_dist = dist; } } } min_dist = std::sqrt(min_dist); Real local_tol = 0.1*min_dist; // find master slave node pairs for (UInt i=0; i<proj_slave_coord.getSize(); ++i) { for (UInt j=0; j<proj_master_coord.getSize(); ++j) { Real dist = 0.; for (UInt d=0; d<dim-1; ++d) { dist += (proj_slave_coord(i,d) - proj_master_coord(j,d)) * (proj_slave_coord(i,d) - proj_master_coord(j,d)); } dist = std::sqrt(dist); if (dist < local_tol) { // it is a pair UInt pair[2]; pair[0] = slave_nodes(i); pair[1] = master_nodes(j); pairs.push_back(pair); continue; // found master do not need to search further for this slave } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::addSurfacePair(const Surface & slave, const Surface & master, UInt surface_normal_dir) { AKANTU_DEBUG_IN(); const Mesh & mesh = this->model.getMesh(); const ElementGroup & slave_boundary = mesh.getElementGroup(slave); const ElementGroup & master_boundary = mesh.getElementGroup(master); this->contact_surfaces.insert(&slave_boundary); this->contact_surfaces.insert(&master_boundary); Array<UInt> pairs(0,2); NTNContact::pairInterfaceNodes(slave_boundary, master_boundary, surface_normal_dir, this->model.getMesh(), pairs); // eliminate pairs which contain a pbc slave node Array<UInt> pairs_no_PBC_slaves(0,2); Array<UInt>::const_vector_iterator it = pairs.begin(2); Array<UInt>::const_vector_iterator end = pairs.end(2); for (; it!=end; ++it) { const Vector<UInt> & pair = *it; if (!this->model.isPBCSlaveNode(pair(0)) && !this->model.isPBCSlaveNode(pair(1))) { pairs_no_PBC_slaves.push_back(pair); } } this->addNodePairs(pairs_no_PBC_slaves); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::addNodePairs(const Array<UInt> & pairs) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(pairs.getNbComponent() == 2, "Array of node pairs should have nb_component = 2," << " but has nb_component = " << pairs.getNbComponent()); UInt nb_pairs = pairs.getSize(); for (UInt n=0; n<nb_pairs; ++n) { this->addSplitNode(pairs(n,0), pairs(n,1)); } // synchronize with depending nodes findBoundaryElements(this->slaves.getArray(), this->slave_elements); findBoundaryElements(this->masters.getArray(), this->master_elements); updateInternalData(); syncArrays(_added); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::getNodePairs(Array<UInt> & pairs) const { AKANTU_DEBUG_IN(); pairs.resize(0); AKANTU_DEBUG_ASSERT(pairs.getNbComponent() == 2, "Array of node pairs should have nb_component = 2," << " but has nb_component = " << pairs.getNbComponent()); UInt nb_pairs = this->getNbContactNodes(); for (UInt n=0; n<nb_pairs; ++n) { UInt pair[2]; pair[0] = this->slaves(n); pair[1] = this->masters(n); pairs.push_back(pair); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::addSplitNode(UInt slave, UInt master) { AKANTU_DEBUG_IN(); NTNBaseContact::addSplitNode(slave); this->masters.push_back(master); this->lumped_boundary_masters.push_back(std::numeric_limits<Real>::quiet_NaN()); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* This function only works for surface elements with one quad point. For surface elements with more quad points, it computes still, but the result might not be what you are looking for. */ void NTNContact::updateNormals() { AKANTU_DEBUG_IN(); // set normals to zero this->normals.clear(); // contact information UInt dim = this->model.getSpatialDimension(); UInt nb_contact_nodes = this->getNbContactNodes(); this->synch_registry->synchronize(_gst_cf_nodal); // synchronize current pos const Array<Real> & cur_pos = this->model.getCurrentPosition(); FEEngine & boundary_fem = this->model.getFEEngineBoundary(); const Mesh & mesh = this->model.getMesh(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator it = mesh.firstType(dim-1, *gt); Mesh::type_iterator last = mesh.lastType(dim-1, *gt); for (; it != last; ++it) { // compute the normals Array<Real> quad_normals(0,dim); boundary_fem.computeNormalsOnIntegrationPoints(cur_pos, quad_normals, *it, *gt); UInt nb_quad_points = boundary_fem.getNbIntegrationPoints(*it, *gt); // new version: compute normals only based on master elements (and not all boundary elements) // ------------------------------------------------------------------------------------- UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); const Array<UInt> & connectivity = mesh.getConnectivity(*it, *gt); Array<UInt>::const_iterator<UInt> elem_it = (this->master_elements)(*it, *gt).begin(); Array<UInt>::const_iterator<UInt> elem_it_end = (this->master_elements)(*it, *gt).end(); // loop over contact nodes for (; elem_it != elem_it_end; ++elem_it) { for (UInt q=0; q<nb_nodes_per_element; ++q) { UInt node = connectivity(*elem_it,q); UInt node_index = this->masters.find(node); AKANTU_DEBUG_ASSERT(node_index != UInt(-1), "Could not find node " << node << " in the array!"); for (UInt q=0; q<nb_quad_points; ++q) { // add quad normal to master normal for (UInt d=0; d<dim; ++d) { this->normals(node_index,d) += quad_normals((*elem_it)*nb_quad_points + q, d); } } } } // ------------------------------------------------------------------------------------- /* // get elements connected to each node CSR<UInt> node_to_element; MeshUtils::buildNode2ElementsElementTypeMap(mesh, node_to_element, *it, *gt); // add up normals to all master nodes for (UInt n=0; n<nb_contact_nodes; ++n) { UInt master = this->masters(n); CSR<UInt>::iterator elem = node_to_element.begin(master); // loop over all elements connected to this master node for (; elem != node_to_element.end(master); ++elem) { UInt e = *elem; // loop over all quad points of this element for (UInt q=0; q<nb_quad_points; ++q) { // add quad normal to master normal for (UInt d=0; d<dim; ++d) { this->normals(n,d) += quad_normals(e*nb_quad_points + q, d); } } } } */ } } Real * master_normals = this->normals.storage(); for (UInt n=0; n<nb_contact_nodes; ++n) { if (dim==2) Math::normalize2(&(master_normals[n*dim])); else if (dim==3) Math::normalize3(&(master_normals[n*dim])); } // // normalize normals - // Array<Real>::iterator<Real> nit = this->normals.begin(); - // Array<Real>::iterator<Real> nend = this->normals.end(); + // auto nit = this->normals.begin(); + // auto nend = this->normals.end(); // for (; nit != nend; ++nit) { // nit->normalize(); // } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::dumpRestart(const std::string & file_name) const { AKANTU_DEBUG_IN(); NTNBaseContact::dumpRestart(file_name); this->masters.dumpRestartFile(file_name); this->lumped_boundary_masters.dumpRestartFile(file_name); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::readRestart(const std::string & file_name) { AKANTU_DEBUG_IN(); NTNBaseContact::readRestart(file_name); this->masters.readRestartFile(file_name); this->lumped_boundary_masters.readRestartFile(file_name); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::updateImpedance() { AKANTU_DEBUG_IN(); UInt nb_contact_nodes = getNbContactNodes(); Real delta_t = this->model.getTimeStep(); AKANTU_DEBUG_ASSERT(delta_t != NAN, "Time step is NAN. Have you set it already?"); const Array<Real> & mass = this->model.getMass(); for (UInt n=0; n<nb_contact_nodes; ++n) { UInt master = this->masters(n); UInt slave = this->slaves(n); Real imp = (this->lumped_boundary_masters(n) / mass(master)) + (this->lumped_boundary_slaves(n) / mass(slave)); imp = 2 / delta_t / imp; this->impedance(n) = imp; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::updateLumpedBoundary() { AKANTU_DEBUG_IN(); internalUpdateLumpedBoundary(this->slaves.getArray(), this->slave_elements, this->lumped_boundary_slaves); internalUpdateLumpedBoundary(this->masters.getArray(), this->master_elements, this->lumped_boundary_masters); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::applyContactPressure() { AKANTU_DEBUG_IN(); UInt nb_ntn_pairs = getNbContactNodes(); UInt dim = this->model.getSpatialDimension(); Array<Real> & residual = this->model.getResidual(); for (UInt n=0; n<nb_ntn_pairs; ++n) { UInt master = this->masters(n); UInt slave = this->slaves(n); for (UInt d=0; d<dim; ++d) { residual(master,d) += this->lumped_boundary_masters(n) * this->contact_pressure(n,d); residual(slave, d) -= this->lumped_boundary_slaves(n) * this->contact_pressure(n,d); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::computeRelativeTangentialField(const Array<Real> & field, Array<Real> & rel_tang_field) const { AKANTU_DEBUG_IN(); // resize arrays to zero rel_tang_field.resize(0); UInt dim = this->model.getSpatialDimension(); - Array<Real>::const_vector_iterator it_field = field.begin(dim); - Array<Real>::const_vector_iterator it_normal = this->normals.getArray().begin(dim); + auto it_field = field.begin(dim); + auto it_normal = this->normals.getArray().begin(dim); Vector<Real> rfv(dim); Vector<Real> np_rfv(dim); UInt nb_contact_nodes = this->slaves.getSize(); for (UInt n=0; n<nb_contact_nodes; ++n) { // nodes UInt slave = this->slaves(n); UInt master = this->masters(n); // relative field vector (slave - master) rfv = Vector<Real>(it_field[slave]); rfv -= Vector<Real>(it_field[master]); // normal projection of relative field const Vector<Real> normal_v = it_normal[n]; np_rfv = normal_v; np_rfv *= rfv.dot(normal_v); // subract normal projection from relative field to get the tangential projection rfv -= np_rfv; rel_tang_field.push_back(rfv); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::computeRelativeNormalField(const Array<Real> & field, Array<Real> & rel_normal_field) const { AKANTU_DEBUG_IN(); // resize arrays to zero rel_normal_field.resize(0); UInt dim = this->model.getSpatialDimension(); // Real * field_p = field.storage(); // Real * normals_p = this->normals.storage(); Array<Real>::const_iterator< Vector<Real> > it_field = field.begin(dim); Array<Real>::const_iterator< Vector<Real> > it_normal = this->normals.getArray().begin(dim); Vector<Real> rfv(dim); UInt nb_contact_nodes = this->getNbContactNodes(); for (UInt n=0; n<nb_contact_nodes; ++n) { // nodes UInt slave = this->slaves(n); UInt master = this->masters(n); // relative field vector (slave - master) rfv = Vector<Real>(it_field[slave]); rfv -= Vector<Real>(it_field[master]); // length of normal projection of relative field const Vector<Real> normal_v = it_normal[n]; rel_normal_field.push_back(rfv.dot(normal_v)); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Int NTNContact::getNodeIndex(UInt node) const { AKANTU_DEBUG_IN(); Int slave_i = NTNBaseContact::getNodeIndex(node); Int master_i = this->masters.find(node); AKANTU_DEBUG_OUT(); return std::max(slave_i,master_i); } /* -------------------------------------------------------------------------- */ void NTNContact::printself(std::ostream & stream, int indent) const { AKANTU_DEBUG_IN(); std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "NTNContact [" << std::endl; NTNBaseContact::printself(stream, indent); stream << space << " + masters : " << std::endl; this->masters.printself(stream, indent + 2); stream << space << " + lumped_boundary_mastres : " << std::endl; this->lumped_boundary_masters.printself(stream, indent + 2); stream << space << "]" << std::endl; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::syncArrays(SyncChoice sync_choice) { AKANTU_DEBUG_IN(); NTNBaseContact::syncArrays(sync_choice); this->masters.syncElements(sync_choice); this->lumped_boundary_masters.syncElements(sync_choice); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNContact::addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { AKANTU_DEBUG_IN(); /* #ifdef AKANTU_USE_IOHELPER const Array<UInt> & nodal_filter = this->slaves.getArray(); #define ADD_FIELD(field_id, field, type) \ internalAddDumpFieldToDumper(dumper_name, \ field_id, \ new DumperIOHelper::NodalField< type, true, \ Array<type>, \ Array<UInt> >(field, 0, 0, &nodal_filter)) */ if(field_id == "lumped_boundary_master") { internalAddDumpFieldToDumper(dumper_name, field_id, new dumper::NodalField<Real>(this->lumped_boundary_masters.getArray())); } else { NTNBaseContact::addDumpFieldToDumper(dumper_name, field_id); } /* #undef ADD_FIELD #endif */ AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/fe_engine/integrator_gauss_inline_impl.cc b/src/fe_engine/integrator_gauss_inline_impl.cc index d3884d56b..adadb20ae 100644 --- a/src/fe_engine/integrator_gauss_inline_impl.cc +++ b/src/fe_engine/integrator_gauss_inline_impl.cc @@ -1,713 +1,706 @@ /** * @file integrator_gauss_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Feb 15 2011 * @date last modification: Thu Nov 19 2015 * * @brief inline function of gauss integrator * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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 "fe_engine.hh" #include "mesh_iterators.hh" #if defined(AKANTU_DEBUG_TOOLS) #include "aka_debug_tools.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { namespace debug { struct IntegratorGaussException : public Exception {}; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::integrateOnElement( const Array<Real> & f, Real * intf, UInt nb_degree_of_freedom, const UInt elem, const GhostType & ghost_type) const { Array<Real> & jac_loc = jacobians(type, ghost_type); UInt nb_quadrature_points = ElementClass<type>::getNbQuadraturePoints(); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom, "The vector f do not have the good number of component."); Real * f_val = f.storage() + elem * f.getNbComponent(); Real * jac_val = jac_loc.storage() + elem * nb_quadrature_points; integrate(f_val, jac_val, intf, nb_degree_of_freedom, nb_quadrature_points); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline Real IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Vector<Real> & in_f, UInt index, const GhostType & ghost_type) const { const Array<Real> & jac_loc = jacobians(type, ghost_type); UInt nb_quadrature_points = GaussIntegrationElement<type>::getNbQuadraturePoints(); AKANTU_DEBUG_ASSERT(in_f.size() == nb_quadrature_points, "The vector f do not have nb_quadrature_points entries."); Real * jac_val = jac_loc.storage() + index * nb_quadrature_points; Real intf; integrate(in_f.storage(), jac_val, &intf, 1, nb_quadrature_points); return intf; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( Real * f, Real * jac, Real * inte, UInt nb_degree_of_freedom, UInt nb_quadrature_points) const { memset(inte, 0, nb_degree_of_freedom * sizeof(Real)); Real * cjac = jac; for (UInt q = 0; q < nb_quadrature_points; ++q) { for (UInt dof = 0; dof < nb_degree_of_freedom; ++dof) { inte[dof] += *f * *cjac; ++f; } ++cjac; } } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline const Matrix<Real> & IntegratorGauss<kind, IntegrationOrderFunctor>::getIntegrationPoints( const GhostType & ghost_type) const { AKANTU_DEBUG_ASSERT( quadrature_points.exists(type, ghost_type), "Quadrature points for type " << quadrature_points.printType(type, ghost_type) << " have not been initialized." << " Did you use 'computeQuadraturePoints' function ?"); return quadrature_points(type, ghost_type); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline UInt IntegratorGauss<kind, IntegrationOrderFunctor>::getNbIntegrationPoints( const GhostType & ghost_type) const { AKANTU_DEBUG_ASSERT( quadrature_points.exists(type, ghost_type), "Quadrature points for type " << quadrature_points.printType(type, ghost_type) << " have not been initialized." << " Did you use 'computeQuadraturePoints' function ?"); return quadrature_points(type, ghost_type).cols(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> inline Matrix<Real> IntegratorGauss<kind, IntegrationOrderFunctor>::getIntegrationPoints() const { return GaussIntegrationElement<type, polynomial_degree>::getQuadraturePoints(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> inline Vector<Real> IntegratorGauss<kind, IntegrationOrderFunctor>::getIntegrationWeights() const { return GaussIntegrationElement<type, polynomial_degree>::getWeights(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::computeQuadraturePoints( const GhostType & ghost_type) { Matrix<Real> & quads = quadrature_points(type, ghost_type); const UInt polynomial_degree = IntegrationOrderFunctor::template getOrder<type>(); quads = GaussIntegrationElement<type, polynomial_degree>::getQuadraturePoints(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>:: computeJacobianOnQuadPointsByElement(const Matrix<Real> & node_coords, const Matrix<Real> & quad, Vector<Real> & jacobians) const { // jacobian ElementClass<type>::computeJacobian(quad, node_coords, jacobians); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> IntegratorGauss<kind, IntegrationOrderFunctor>::IntegratorGauss( const Mesh & mesh, const ID & id, const MemoryID & memory_id) : Integrator(mesh, id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>::checkJacobians( const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = this->quadrature_points(type, ghost_type).cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); Real * jacobians_val = jacobians(type, ghost_type).storage(); for (UInt i = 0; i < nb_element * nb_quadrature_points; ++i, ++jacobians_val) { if (*jacobians_val < 0) AKANTU_CUSTOM_EXCEPTION_INFO(debug::IntegratorGaussException{}, "Negative jacobian computed," << " possible problem in the element node ordering (Quadrature Point " << i % nb_quadrature_points << ":" << i / nb_quadrature_points << ":" << type << ":" << ghost_type << ")"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = quad_points.cols(); UInt nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); auto jacobians_begin = jacobians_it; Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = x_el.begin(spatial_dimension, nb_nodes_per_element); nb_element = x_el.size(); // Matrix<Real> local_coord(spatial_dimension, nb_nodes_per_element); for (UInt elem = 0; elem < nb_element; ++elem, ++x_it) { const Matrix<Real> & x = *x_it; Vector<Real> & J = *jacobians_it; computeJacobianOnQuadPointsByElement<type>(x, quad_points, J); if (filter_elements == empty_filter) { ++jacobians_it; } else { jacobians_it = jacobians_begin + filter_elements(elem); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_STRUCTURAL_MECHANICS) template <> template <ElementType type> void IntegratorGauss<_ek_structural, DefaultIntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); const UInt spatial_dimension = mesh.getSpatialDimension(); const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const UInt nb_quadrature_points = quad_points.cols(); const UInt nb_dofs = ElementClass<type>::getNbDegreeOfFreedom(); UInt nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); auto jacobians_begin = jacobians_it; Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = x_el.begin(spatial_dimension, nb_nodes_per_element); nb_element = x_el.size(); const bool has_extra_normal = mesh.hasData<Real>("extra_normal", type, ghost_type); Array<Real>::const_vector_iterator extra_normal, extra_normal_begin; if (has_extra_normal) { extra_normal = mesh.getData<Real>("extra_normal", type, ghost_type) .begin(spatial_dimension); extra_normal_begin = extra_normal; } // Matrix<Real> local_coord(spatial_dimension, nb_nodes_per_element); for (UInt elem = 0; elem < nb_element; ++elem, ++x_it) { const Matrix<Real> & X = *x_it; Vector<Real> & J = *jacobians_it; Matrix<Real> R(nb_dofs, nb_dofs); if (has_extra_normal) ElementClass<type>::computeRotationMatrix(R, X, *extra_normal); else ElementClass<type>::computeRotationMatrix(R, X, Vector<Real>(X.rows())); // Extracting relevant lines auto x = (R.block(0, 0, spatial_dimension, spatial_dimension) * X) .block(0, 0, ElementClass<type>::getNaturalSpaceDimension(), ElementClass<type>::getNbNodesPerElement()); computeJacobianOnQuadPointsByElement<type>(x, quad_points, J); if (filter_elements == empty_filter) { ++jacobians_it; ++extra_normal; } else { jacobians_it = jacobians_begin + filter_elements(elem); extra_normal = extra_normal_begin + filter_elements(elem); } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) template <> template <ElementType type> void IntegratorGauss<_ek_cohesive, DefaultIntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & quad_points, Array<Real> & jacobians, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = quad_points.cols(); UInt nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); auto jacobians_begin = jacobians_it; Vector<Real> weights = GaussIntegrationElement<type>::getWeights(); Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = x_el.begin(spatial_dimension, nb_nodes_per_element); UInt nb_nodes_per_subelement = nb_nodes_per_element / 2; Matrix<Real> x(spatial_dimension, nb_nodes_per_subelement); nb_element = x_el.size(); auto compute = [&](const auto & el) { Vector<Real> J(jacobians_begin[el]); for (UInt s = 0; s < spatial_dimension; ++s) for (UInt n = 0; n < nb_nodes_per_subelement; ++n) x(s, n) = ((*x_it)(s, n) + (*x_it)(s, n + nb_nodes_per_subelement)) * .5; if (type == _cohesive_1d_2) J(0) = 1; else this->computeJacobianOnQuadPointsByElement<type>(x, quad_points, J); }; - for_each_element(nb_element, filter_elements, compute); - - - AKANTU_DEBUG_OUT(); + for_each_element(nb_element, filter_elements, compute);AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>:: precomputeJacobiansOnQuadraturePoints(const Array<Real> & nodes, - const GhostType & ghost_type) { + const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Array<Real> & jacobians_tmp = jacobians.alloc(0, 1, type, ghost_type); this->computeJacobiansOnIntegrationPoints<type>( nodes, quadrature_points(type, ghost_type), jacobians_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> void IntegratorGauss<kind, IntegrationOrderFunctor>::multiplyJacobiansByWeights( Array<Real> & jacobians) const { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = GaussIntegrationElement<type, polynomial_degree>::getNbQuadraturePoints(); UInt nb_element = jacobians.size() / nb_quadrature_points; Vector<Real> weights = GaussIntegrationElement<type, polynomial_degree>::getWeights(); - Array<Real>::vector_iterator jacobians_it = + auto jacobians_it = jacobians.begin_reinterpret(nb_quadrature_points, nb_element); - Array<Real>::vector_iterator jacobians_end = + auto jacobians_end = jacobians.end_reinterpret(nb_quadrature_points, nb_element); for (; jacobians_it != jacobians_end; ++jacobians_it) { Vector<Real> & J = *jacobians_it; J *= weights; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const Array<Real> & jacobians, UInt nb_element) const { AKANTU_DEBUG_IN(); intf.resize(nb_element); if (nb_element == 0) return; UInt nb_points = jacobians.size() / nb_element; Array<Real>::const_matrix_iterator J_it; Array<Real>::matrix_iterator inte_it; Array<Real>::const_matrix_iterator f_it; f_it = in_f.begin_reinterpret(nb_degree_of_freedom, nb_points, nb_element); inte_it = intf.begin_reinterpret(nb_degree_of_freedom, 1, nb_element); J_it = jacobians.begin_reinterpret(nb_points, 1, nb_element); for (UInt el = 0; el < nb_element; ++el, ++J_it, ++f_it, ++inte_it) { const Matrix<Real> & f = *f_it; const Matrix<Real> & J = *J_it; Matrix<Real> & inte_f = *inte_it; inte_f.mul<false, false>(f, J); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), - "No jacobians for the type " - << jacobians.printType(type, ghost_type)); + "No jacobians for the type " + << jacobians.printType(type, ghost_type)); const Array<Real> & jac_loc = jacobians(type, ghost_type); if (filter_elements != empty_filter) { UInt nb_element = filter_elements.size(); Array<Real> * filtered_J = new Array<Real>(0, jac_loc.getNbComponent()); FEEngine::filterElementalData(mesh, jac_loc, *filtered_J, type, ghost_type, - filter_elements); + filter_elements); this->integrate(in_f, intf, nb_degree_of_freedom, *filtered_J, nb_element); delete filtered_J; } else { UInt nb_element = mesh.getNbElement(type, ghost_type); this->integrate(in_f, intf, nb_degree_of_freedom, jac_loc, nb_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> void IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, Array<Real> & intf, UInt nb_degree_of_freedom, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); Matrix<Real> quads = this->getIntegrationPoints<type, polynomial_degree>(); Array<Real> jacobians; this->computeJacobiansOnIntegrationPoints<type>(mesh.getNodes(), quads, - jacobians, ghost_type); + jacobians, ghost_type); this->multiplyJacobiansByWeights<type, polynomial_degree>(jacobians); this->integrate(in_f, intf, nb_degree_of_freedom, jacobians, - mesh.getNbElement(type, ghost_type)); + mesh.getNbElement(type, ghost_type)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type, UInt polynomial_degree> Real IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); Array<Real> intfv(0, 1); integrate<type, polynomial_degree>(in_f, intfv, 1, ghost_type); Real res = Math::reduce(intfv); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> Real IntegratorGauss<kind, IntegrationOrderFunctor>::integrate( const Array<Real> & in_f, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), - "No jacobians for the type " - << jacobians.printType(type, ghost_type)); + "No jacobians for the type " + << jacobians.printType(type, ghost_type)); Array<Real> intfv(0, 1); integrate<type>(in_f, intfv, 1, ghost_type, filter_elements); Real res = Math::reduce(intfv); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>:: integrateOnIntegrationPoints(const Array<Real> & in_f, Array<Real> & intf, - UInt nb_degree_of_freedom, - const Array<Real> & jacobians, - UInt nb_element) const { + UInt nb_degree_of_freedom, + const Array<Real> & jacobians, + UInt nb_element) const { AKANTU_DEBUG_IN(); UInt nb_points = jacobians.size() / nb_element; - Array<Real>::const_scalar_iterator J_it; - Array<Real>::vector_iterator inte_it; - Array<Real>::const_vector_iterator f_it; - intf.resize(nb_element * nb_points); - J_it = jacobians.begin(); - f_it = in_f.begin(nb_degree_of_freedom); - inte_it = intf.begin(nb_degree_of_freedom); + auto J_it = jacobians.begin(); + auto f_it = in_f.begin(nb_degree_of_freedom); + auto inte_it = intf.begin(nb_degree_of_freedom); for (UInt el = 0; el < nb_element; ++el, ++J_it, ++f_it, ++inte_it) { const Real & J = *J_it; const Vector<Real> & f = *f_it; Vector<Real> & inte_f = *inte_it; inte_f = f; inte_f *= J; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> void IntegratorGauss<kind, IntegrationOrderFunctor>:: integrateOnIntegrationPoints(const Array<Real> & in_f, Array<Real> & intf, - UInt nb_degree_of_freedom, - const GhostType & ghost_type, - const Array<UInt> & filter_elements) const { + UInt nb_degree_of_freedom, + const GhostType & ghost_type, + const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), - "No jacobians for the type " - << jacobians.printType(type, ghost_type)); + "No jacobians for the type " + << jacobians.printType(type, ghost_type)); const Array<Real> & jac_loc = this->jacobians(type, ghost_type); if (filter_elements != empty_filter) { UInt nb_element = filter_elements.size(); Array<Real> * filtered_J = new Array<Real>(0, jac_loc.getNbComponent()); FEEngine::filterElementalData(mesh, jac_loc, *filtered_J, type, ghost_type, - filter_elements); + filter_elements); this->integrateOnIntegrationPoints(in_f, intf, nb_degree_of_freedom, - *filtered_J, nb_element); + *filtered_J, nb_element); } else { UInt nb_element = mesh.getNbElement(type, ghost_type); this->integrateOnIntegrationPoints(in_f, intf, nb_degree_of_freedom, - jac_loc, nb_element); + jac_loc, nb_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>::onElementsAdded( const Array<Element> & new_elements) { const auto & nodes = mesh.getNodes(); for (auto elements_range : MeshElementsByTypes(new_elements)) { auto type = elements_range.getType(); auto ghost_type = elements_range.getGhostType(); if (mesh.getKind(type) != kind) continue; auto & elements = elements_range.getElements(); if (not jacobians.exists(type, ghost_type)) jacobians.alloc(0, 1, type, ghost_type); this->computeJacobiansOnIntegrationPoints( - nodes, quadrature_points(type, ghost_type), jacobians(type, ghost_type), - type, ghost_type, elements); + nodes, quadrature_points(type, ghost_type), jacobians(type, ghost_type), + type, ghost_type, elements); } } /* -------------------------------------------------------------------------- */ template <ElementKind kind, class IntegrationOrderFunctor> template <ElementType type> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::initIntegrator( const Array<Real> & nodes, const GhostType & ghost_type) { computeQuadraturePoints<type>(ghost_type); precomputeJacobiansOnQuadraturePoints<type>(nodes, ghost_type); checkJacobians<type>(ghost_type); constexpr UInt polynomial_degree = IntegrationOrderFunctor::template getOrder<type>(); multiplyJacobiansByWeights<type, polynomial_degree>( this->jacobians(type, ghost_type)); } namespace integrator { namespace details { template <ElementKind kind> struct GaussIntegratorInitHelper {}; #define INIT_INTEGRATOR(type) \ _int.template initIntegrator<type>(nodes, ghost_type) #define AKANTU_GAUSS_INTERGRATOR_INIT_HELPER(kind) \ template <> struct GaussIntegratorInitHelper<kind> { \ template <ElementKind k, class IOF> \ static void call(IntegratorGauss<k, IOF> & _int, \ - const Array<Real> & nodes, const ElementType & type, \ - const GhostType & ghost_type) { \ + const Array<Real> & nodes, const ElementType & type, \ + const GhostType & ghost_type) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(INIT_INTEGRATOR, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_GAUSS_INTERGRATOR_INIT_HELPER) #undef AKANTU_GAUSS_INTERGRATOR_INIT_HELPER #undef INIT_INTEGRATOR } // namespace details } // namespace integrator template <ElementKind kind, class IntegrationOrderFunctor> inline void IntegratorGauss<kind, IntegrationOrderFunctor>::initIntegrator( const Array<Real> & nodes, const ElementType & type, const GhostType & ghost_type) { integrator::details::GaussIntegratorInitHelper<kind>::call(*this, nodes, type, - ghost_type); + ghost_type); } namespace integrator { namespace details { template <ElementKind kind> struct GaussIntegratorComputeJacobiansHelper {}; #define AKANTU_COMPUTE_JACOBIANS(type) \ _int.template computeJacobiansOnIntegrationPoints<type>( \ nodes, quad_points, jacobians, ghost_type, filter_elements); #define AKANTU_GAUSS_INTERGRATOR_COMPUTE_JACOBIANS(kind) \ template <> struct GaussIntegratorComputeJacobiansHelper<kind> { \ template <ElementKind k, class IOF> \ static void \ call(const IntegratorGauss<k, IOF> & _int, const Array<Real> & nodes, \ - const Matrix<Real> & quad_points, Array<Real> & jacobians, \ - const ElementType & type, const GhostType & ghost_type, \ - const Array<UInt> & filter_elements) { \ + const Matrix<Real> & quad_points, Array<Real> & jacobians, \ + const ElementType & type, const GhostType & ghost_type, \ + const Array<UInt> & filter_elements) { \ AKANTU_BOOST_KIND_ELEMENT_SWITCH(AKANTU_COMPUTE_JACOBIANS, kind); \ } \ }; AKANTU_BOOST_ALL_KIND(AKANTU_GAUSS_INTERGRATOR_COMPUTE_JACOBIANS) #undef AKANTU_GAUSS_INTERGRATOR_COMPUTE_JACOBIANS #undef AKANTU_COMPUTE_JACOBIANS } // namespace details } // namespace integrator template <ElementKind kind, class IntegrationOrderFunctor> void IntegratorGauss<kind, IntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( - const Array<Real> & nodes, const Matrix<Real> & quad_points, - Array<Real> & jacobians, const ElementType & type, - const GhostType & ghost_type, - const Array<UInt> & filter_elements) const { + const Array<Real> & nodes, const Matrix<Real> & quad_points, + Array<Real> & jacobians, const ElementType & type, + const GhostType & ghost_type, + const Array<UInt> & filter_elements) const { integrator::details::GaussIntegratorComputeJacobiansHelper<kind>::call( *this, nodes, quad_points, jacobians, type, ghost_type, filter_elements); } } // namespace akantu diff --git a/src/geometry/mesh_sphere_intersector_tmpl.hh b/src/geometry/mesh_sphere_intersector_tmpl.hh index d95d86710..f02b004c6 100644 --- a/src/geometry/mesh_sphere_intersector_tmpl.hh +++ b/src/geometry/mesh_sphere_intersector_tmpl.hh @@ -1,195 +1,195 @@ /** * @file mesh_sphere_intersector_tmpl.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jun 23 2015 * @date last modification: Thu Jan 14 2016 * * @brief Computation of mesh intersection with spheres * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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_SPHERE_INTERSECTOR_TMPL_HH__ #define __AKANTU_MESH_SPHERE_INTERSECTOR_TMPL_HH__ #include "aka_common.hh" #include "mesh_geom_common.hh" #include "tree_type_helper.hh" #include "mesh_sphere_intersector.hh" namespace akantu { template<UInt dim, ElementType type> MeshSphereIntersector<dim, type>::MeshSphereIntersector(Mesh & mesh): parent_type(mesh), tol_intersection_on_node(1e-10) { #if defined(AKANTU_IGFEM) if( (type == _triangle_3) || (type == _igfem_triangle_4) || (type == _igfem_triangle_5) ){ const_cast<UInt &>(this->nb_seg_by_el) = 3; } else { AKANTU_ERROR("Not ready for mesh type " << type); } #else if( (type != _triangle_3) ) AKANTU_ERROR("Not ready for mesh type " << type); #endif // initialize the intersection pointsss array with the spatial dimension this->intersection_points = new Array<Real>(0,dim); // A maximum is set to the number of intersection nodes per element to limit the size of new_node_per_elem: 2 in 2D and 4 in 3D this->new_node_per_elem = new Array<UInt>(0, 1 + 4 * (dim-1)); } template<UInt dim, ElementType type> MeshSphereIntersector<dim, type>::~MeshSphereIntersector() { delete this->new_node_per_elem; delete this->intersection_points; } template<UInt dim, ElementType type> void MeshSphereIntersector<dim, type>::constructData(GhostType ghost_type) { this->new_node_per_elem->resize(this->mesh.getNbElement(type, ghost_type)); this->new_node_per_elem->clear(); MeshGeomIntersector<dim, type, Line_arc<SK>, SK::Sphere_3, SK>::constructData(ghost_type); } template<UInt dim, ElementType type> void MeshSphereIntersector<dim, type>:: computeMeshQueryIntersectionPoint(const SK::Sphere_3 & query, UInt nb_old_nodes) { /// function to replace computeIntersectionQuery in a more generic geometry module version // The newNodeEvent is not send from this method who only compute the intersection points AKANTU_DEBUG_IN(); Array<Real> & nodes = this->mesh.getNodes(); UInt nb_node = nodes.size() + this->intersection_points->size(); // Tolerance for proximity checks should be defined by user Real global_tolerance = Math::getTolerance(); Math::setTolerance(tol_intersection_on_node); typedef boost::variant<pair_type> sk_inter_res; TreeTypeHelper<Line_arc<cgal::Spherical>, cgal::Spherical>::const_iterator it = this->factory.getPrimitiveList().begin(), end= this->factory.getPrimitiveList().end(); for (; it != end ; ++it) { // loop on the primitives (segments) std::list<sk_inter_res> s_results; CGAL::intersection(*it, query, std::back_inserter(s_results)); if (s_results.size() == 1) { // just one point if (pair_type * pair = boost::get<pair_type>(&s_results.front())) { if (pair->second == 1) { // not a point tangent to the sphere // the intersection point written as a vector Vector<Real> new_node(dim, 0.0); cgal::Cartesian::Point_3 point(CGAL::to_double(pair->first.x()), CGAL::to_double(pair->first.y()), CGAL::to_double(pair->first.z())); for (UInt i = 0 ; i < dim ; i++) { new_node(i) = point[i]; } /// boolean to decide wheter intersection point is on a standard node of the mesh or not bool is_on_mesh = false; /// boolean to decide if this intersection point has been already computed for a neighbor element bool is_new = true; /// check if intersection point has already been computed UInt n = nb_old_nodes; // check if we already compute this intersection and add it as a node for a neighboor element of another type - Array<Real>::vector_iterator existing_node = nodes.begin(dim); + auto existing_node = nodes.begin(dim); for (; n < nodes.size() ; ++n) {// loop on the nodes from nb_old_nodes if (Math::are_vector_equal(dim, new_node.storage(), existing_node[n].storage())) { is_new = false; break; } } if(is_new){ - Array<Real>::vector_iterator intersection_points_it = this->intersection_points->begin(dim); - Array<Real>::vector_iterator intersection_points_end = this->intersection_points->end(dim); + auto intersection_points_it = this->intersection_points->begin(dim); + auto intersection_points_end = this->intersection_points->end(dim); for (; intersection_points_it != intersection_points_end ; ++intersection_points_it, ++n) { if (Math::are_vector_equal(dim, new_node.storage(), intersection_points_it->storage())) { is_new = false; break; } } } // get the initial and final points of the primitive (segment) and write them as vectors cgal::Cartesian::Point_3 source_cgal(CGAL::to_double(it->source().x()), CGAL::to_double(it->source().y()), CGAL::to_double(it->source().z())); cgal::Cartesian::Point_3 target_cgal(CGAL::to_double(it->target().x()), CGAL::to_double(it->target().y()), CGAL::to_double(it->target().z())); Vector<Real> source(dim), target(dim); for (UInt i = 0 ; i < dim ; i++) { source(i) = source_cgal[i]; target(i) = target_cgal[i]; } // Check if we are close from a node of the primitive (segment) if (Math::are_vector_equal(dim, source.storage(), new_node.storage()) || Math::are_vector_equal(dim, target.storage(), new_node.storage())) { is_on_mesh = true; is_new = false; } if (is_new) {// if the intersection point is a new one add it to the list this->intersection_points->push_back(new_node); nb_node++; } // deduce the element id UInt element_id = it->id(); // fill the new_node_per_elem array if (!is_on_mesh) { // if the node is not on a mesh node UInt & nb_new_nodes_per_el = (*this->new_node_per_elem)(element_id, 0); nb_new_nodes_per_el += 1; AKANTU_DEBUG_ASSERT(2 * nb_new_nodes_per_el < this->new_node_per_elem->getNbComponent(), "You might have to interface crossing the same material"); (*this->new_node_per_elem)(element_id, (2 * nb_new_nodes_per_el) - 1) = n; (*this->new_node_per_elem)(element_id, 2 * nb_new_nodes_per_el) = it->segId(); } } } } } Math::setTolerance(global_tolerance); AKANTU_DEBUG_OUT(); } } // akantu #endif // __AKANTU_MESH_SPHERE_INTERSECTOR_TMPL_HH__ diff --git a/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc b/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc index c50f985ac..1721808e0 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc +++ b/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc @@ -1,481 +1,481 @@ /** * @file mesh_partition_scotch.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Jan 22 2016 * * @brief implementation of the MeshPartitionScotch class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_partition_scotch.hh" #include "aka_common.hh" #include "aka_random_generator.hh" #include "aka_static_if.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <cstdio> #include <fstream> /* -------------------------------------------------------------------------- */ #if !defined(AKANTU_USE_PTSCOTCH) #ifndef AKANTU_SCOTCH_NO_EXTERN extern "C" { #endif // AKANTU_SCOTCH_NO_EXTERN #include <scotch.h> #ifndef AKANTU_SCOTCH_NO_EXTERN } #endif // AKANTU_SCOTCH_NO_EXTERN #else // AKANTU_USE_PTSCOTCH #include <ptscotch.h> #endif // AKANTU_USE_PTSCOTCH namespace akantu { namespace { constexpr int scotch_version = int(SCOTCH_VERSION); } /* -------------------------------------------------------------------------- */ MeshPartitionScotch::MeshPartitionScotch(const Mesh & mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : MeshPartition(mesh, spatial_dimension, id, memory_id) { AKANTU_DEBUG_IN(); // check if the akantu types and Scotch one are consistent static_assert( sizeof(Int) == sizeof(SCOTCH_Num), "The integer type of Akantu does not match the one from Scotch"); static_if(aka::bool_constant_v<scotch_version >= 6>) .then([](auto && y) { SCOTCH_randomSeed(y); }) .else_([](auto && y) { srandom(y); })(std::forward<UInt>(RandomGenerator<UInt>::seed())); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ static SCOTCH_Mesh * createMesh(const Mesh & mesh) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes = mesh.getNbNodes(); UInt total_nb_element = 0; UInt nb_edge = 0; Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator end = mesh.lastType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); total_nb_element += nb_element; nb_edge += nb_element * nb_nodes_per_element; } SCOTCH_Num vnodbas = 0; SCOTCH_Num vnodnbr = nb_nodes; SCOTCH_Num velmbas = vnodnbr; SCOTCH_Num velmnbr = total_nb_element; auto * verttab = new SCOTCH_Num[vnodnbr + velmnbr + 1]; SCOTCH_Num * vendtab = verttab + 1; SCOTCH_Num * velotab = nullptr; SCOTCH_Num * vnlotab = nullptr; SCOTCH_Num * vlbltab = nullptr; memset(verttab, 0, (vnodnbr + velmnbr + 1) * sizeof(SCOTCH_Num)); it = mesh.firstType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; if (Mesh::getSpatialDimension(type) != spatial_dimension) continue; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<UInt> & connectivity = mesh.getConnectivity(type, _not_ghost); /// count number of occurrence of each node for (UInt el = 0; el < nb_element; ++el) { UInt * conn_val = connectivity.storage() + el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { verttab[*(conn_val++)]++; } } } /// convert the occurrence array in a csr one for (UInt i = 1; i < nb_nodes; ++i) verttab[i] += verttab[i - 1]; for (UInt i = nb_nodes; i > 0; --i) verttab[i] = verttab[i - 1]; verttab[0] = 0; /// rearrange element to get the node-element list SCOTCH_Num edgenbr = verttab[vnodnbr] + nb_edge; auto * edgetab = new SCOTCH_Num[edgenbr]; UInt linearized_el = 0; it = mesh.firstType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<UInt> & connectivity = mesh.getConnectivity(type, _not_ghost); for (UInt el = 0; el < nb_element; ++el, ++linearized_el) { UInt * conn_val = connectivity.storage() + el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) edgetab[verttab[*(conn_val++)]++] = linearized_el + velmbas; } } for (UInt i = nb_nodes; i > 0; --i) verttab[i] = verttab[i - 1]; verttab[0] = 0; SCOTCH_Num * verttab_tmp = verttab + vnodnbr + 1; SCOTCH_Num * edgetab_tmp = edgetab + verttab[vnodnbr]; it = mesh.firstType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<UInt> & connectivity = mesh.getConnectivity(type, _not_ghost); for (UInt el = 0; el < nb_element; ++el) { *verttab_tmp = *(verttab_tmp - 1) + nb_nodes_per_element; verttab_tmp++; UInt * conn = connectivity.storage() + el * nb_nodes_per_element; for (UInt i = 0; i < nb_nodes_per_element; ++i) { *(edgetab_tmp++) = *(conn++) + vnodbas; } } } auto * meshptr = new SCOTCH_Mesh; SCOTCH_meshInit(meshptr); SCOTCH_meshBuild(meshptr, velmbas, vnodbas, velmnbr, vnodnbr, verttab, vendtab, velotab, vnlotab, vlbltab, edgenbr, edgetab); /// Check the mesh AKANTU_DEBUG_ASSERT(SCOTCH_meshCheck(meshptr) == 0, "Scotch mesh is not consistent"); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { /// save initial graph FILE * fmesh = fopen("ScotchMesh.msh", "w"); SCOTCH_meshSave(meshptr, fmesh); fclose(fmesh); /// write geometry file std::ofstream fgeominit; fgeominit.open("ScotchMesh.xyz"); fgeominit << spatial_dimension << std::endl << nb_nodes << std::endl; const Array<Real> & nodes = mesh.getNodes(); Real * nodes_val = nodes.storage(); for (UInt i = 0; i < nb_nodes; ++i) { fgeominit << i << " "; for (UInt s = 0; s < spatial_dimension; ++s) fgeominit << *(nodes_val++) << " "; fgeominit << std::endl; ; } fgeominit.close(); } #endif AKANTU_DEBUG_OUT(); return meshptr; } /* -------------------------------------------------------------------------- */ static void destroyMesh(SCOTCH_Mesh * meshptr) { AKANTU_DEBUG_IN(); SCOTCH_Num velmbas, vnodbas, vnodnbr, velmnbr, *verttab, *vendtab, *velotab, *vnlotab, *vlbltab, edgenbr, *edgetab, degrptr; SCOTCH_meshData(meshptr, &velmbas, &vnodbas, &velmnbr, &vnodnbr, &verttab, &vendtab, &velotab, &vnlotab, &vlbltab, &edgenbr, &edgetab, °rptr); delete[] verttab; delete[] edgetab; SCOTCH_meshExit(meshptr); delete meshptr; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartitionScotch::partitionate(UInt nb_part, const EdgeLoadFunctor & edge_load_func, const Array<UInt> & pairs) { AKANTU_DEBUG_IN(); nb_partitions = nb_part; tweakConnectivity(pairs); AKANTU_DEBUG_INFO("Partitioning the mesh " << mesh.getID() << " in " << nb_part << " parts."); Array<Int> dxadj; Array<Int> dadjncy; Array<Int> edge_loads; buildDualGraph(dxadj, dadjncy, edge_loads, edge_load_func); /// variables that will hold our structures in scotch format SCOTCH_Graph scotch_graph; SCOTCH_Strat scotch_strat; /// description number and arrays for struct mesh for scotch SCOTCH_Num baseval = 0; // base numbering for element and // nodes (0 -> C , 1 -> fortran) SCOTCH_Num vertnbr = dxadj.size() - 1; // number of vertexes SCOTCH_Num * parttab; // array of partitions SCOTCH_Num edgenbr = dxadj(vertnbr); // twice the number of "edges" //(an "edge" bounds two nodes) SCOTCH_Num * verttab = dxadj.storage(); // array of start indices in edgetab SCOTCH_Num * vendtab = nullptr; // array of after-last indices in edgetab SCOTCH_Num * velotab = nullptr; // integer load associated with // every vertex ( optional ) SCOTCH_Num * edlotab = edge_loads.storage(); // integer load associated with // every edge ( optional ) SCOTCH_Num * edgetab = dadjncy.storage(); // adjacency array of every vertex SCOTCH_Num * vlbltab = nullptr; // vertex label array (optional) /// Allocate space for Scotch arrays parttab = new SCOTCH_Num[vertnbr]; /// Initialize the strategy structure SCOTCH_stratInit(&scotch_strat); /// Initialize the graph structure SCOTCH_graphInit(&scotch_graph); /// Build the graph from the adjacency arrays SCOTCH_graphBuild(&scotch_graph, baseval, vertnbr, verttab, vendtab, velotab, vlbltab, edgenbr, edgetab, edlotab); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { /// save initial graph FILE * fgraphinit = fopen("GraphIniFile.grf", "w"); SCOTCH_graphSave(&scotch_graph, fgraphinit); fclose(fgraphinit); /// write geometry file std::ofstream fgeominit; fgeominit.open("GeomIniFile.xyz"); fgeominit << spatial_dimension << std::endl << vertnbr << std::endl; const Array<Real> & nodes = mesh.getNodes(); Mesh::type_iterator f_it = mesh.firstType(spatial_dimension, _not_ghost, _ek_not_defined); Mesh::type_iterator f_end = mesh.lastType(spatial_dimension, _not_ghost, _ek_not_defined); - Array<Real>::const_vector_iterator nodes_it = + auto nodes_it = nodes.begin(spatial_dimension); UInt out_linerized_el = 0; for (; f_it != f_end; ++f_it) { ElementType type = *f_it; UInt nb_element = mesh.getNbElement(*f_it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<UInt> & connectivity = mesh.getConnectivity(type); Vector<Real> mid(spatial_dimension); for (UInt el = 0; el < nb_element; ++el) { mid.set(0.); for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity.storage()[nb_nodes_per_element * el + n]; mid += Vector<Real>(nodes_it[node]); } mid /= nb_nodes_per_element; fgeominit << out_linerized_el++ << " "; for (UInt s = 0; s < spatial_dimension; ++s) fgeominit << mid[s] << " "; fgeominit << std::endl; ; } } fgeominit.close(); } #endif /// Check the graph AKANTU_DEBUG_ASSERT(SCOTCH_graphCheck(&scotch_graph) == 0, "Graph to partition is not consistent"); /// Partition the mesh SCOTCH_graphPart(&scotch_graph, nb_part, &scotch_strat, parttab); /// Check the graph AKANTU_DEBUG_ASSERT(SCOTCH_graphCheck(&scotch_graph) == 0, "Partitioned graph is not consistent"); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { /// save the partitioned graph FILE * fgraph = fopen("GraphFile.grf", "w"); SCOTCH_graphSave(&scotch_graph, fgraph); fclose(fgraph); /// save the partition map std::ofstream fmap; fmap.open("MapFile.map"); fmap << vertnbr << std::endl; for (Int i = 0; i < vertnbr; i++) fmap << i << " " << parttab[i] << std::endl; fmap.close(); } #endif /// free the scotch data structures SCOTCH_stratExit(&scotch_strat); SCOTCH_graphFree(&scotch_graph); SCOTCH_graphExit(&scotch_graph); fillPartitionInformation(mesh, parttab); delete[] parttab; restoreConnectivity(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartitionScotch::reorder() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Reordering the mesh " << mesh.getID()); SCOTCH_Mesh * scotch_mesh = createMesh(mesh); UInt nb_nodes = mesh.getNbNodes(); SCOTCH_Strat scotch_strat; // SCOTCH_Ordering scotch_order; auto * permtab = new SCOTCH_Num[nb_nodes]; SCOTCH_Num * peritab = nullptr; SCOTCH_Num cblknbr = 0; SCOTCH_Num * rangtab = nullptr; SCOTCH_Num * treetab = nullptr; /// Initialize the strategy structure SCOTCH_stratInit(&scotch_strat); SCOTCH_Graph scotch_graph; SCOTCH_graphInit(&scotch_graph); SCOTCH_meshGraph(scotch_mesh, &scotch_graph); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { FILE * fgraphinit = fopen("ScotchMesh.grf", "w"); SCOTCH_graphSave(&scotch_graph, fgraphinit); fclose(fgraphinit); } #endif /// Check the graph // AKANTU_DEBUG_ASSERT(SCOTCH_graphCheck(&scotch_graph) == 0, // "Mesh to Graph is not consistent"); SCOTCH_graphOrder(&scotch_graph, &scotch_strat, permtab, peritab, &cblknbr, rangtab, treetab); SCOTCH_graphExit(&scotch_graph); SCOTCH_stratExit(&scotch_strat); destroyMesh(scotch_mesh); /// Renumbering UInt spatial_dimension = mesh.getSpatialDimension(); for (UInt g = _not_ghost; g <= _ghost; ++g) { auto gt = (GhostType)g; Mesh::type_iterator it = mesh.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh.lastType(_all_dimensions, gt); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, gt); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<UInt> & connectivity = mesh.getConnectivity(type, gt); UInt * conn = connectivity.storage(); for (UInt el = 0; el < nb_element * nb_nodes_per_element; ++el, ++conn) { *conn = permtab[*conn]; } } } /// \todo think of a in-place way to do it auto * new_coordinates = new Real[spatial_dimension * nb_nodes]; Real * old_coordinates = mesh.getNodes().storage(); for (UInt i = 0; i < nb_nodes; ++i) { memcpy(new_coordinates + permtab[i] * spatial_dimension, old_coordinates + i * spatial_dimension, spatial_dimension * sizeof(Real)); } memcpy(old_coordinates, new_coordinates, nb_nodes * spatial_dimension * sizeof(Real)); delete[] new_coordinates; delete[] permtab; AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 93f8e8090..7cd39ff8a 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2173 +1,2173 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Aug 20 2010 * @date last modification: Fri Jan 22 2016 * * @brief All mesh utils necessary for various tasks * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "fe_engine.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #include <limits> #include <numeric> #include <queue> #include <set> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<Element> & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); /// count number of occurrence of each node UInt nb_nodes = mesh.getNbNodes(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); AKANTU_DEBUG_ASSERT( mesh.firstType(spatial_dimension) != mesh.lastType(spatial_dimension), "Some elements must be found in right dimension to compute facets!"); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); for (; first != last; ++first) { ElementType type = *first; UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator<Vector<UInt>> conn_it = mesh.getConnectivity(type, *gt).begin( Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) for (UInt n = 0; n < conn_it->size(); ++n) ++node_to_elem.rowOffset((*conn_it)(n)); } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); /// rearrange element to get the node-element list Element e; node_to_elem.beginInsertions(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); e.ghost_type = *gt; for (; first != last; ++first) { ElementType type = *first; e.type = type; UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator<Vector<UInt>> conn_it = mesh.getConnectivity(type, *gt).begin( Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; for (UInt n = 0; n < conn_it->size(); ++n) node_to_elem.insertInRow((*conn_it)(n), e); } } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This function should disappear in the future (used in mesh partitioning) */ // void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<UInt> & // node_to_elem, // UInt spatial_dimension) { // AKANTU_DEBUG_IN(); // if (spatial_dimension == _all_dimensions) // spatial_dimension = mesh.getSpatialDimension(); // UInt nb_nodes = mesh.getNbNodes(); // const Mesh::ConnectivityTypeList & type_list = // mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator // it; // UInt nb_types = type_list.size(); // UInt nb_good_types = 0; // Vector<UInt> nb_nodes_per_element(nb_types); // UInt ** conn_val = new UInt *[nb_types]; // Vector<UInt> nb_element(nb_types); // for (it = type_list.begin(); it != type_list.end(); ++it) { // ElementType type = *it; // if (Mesh::getSpatialDimension(type) != spatial_dimension) // continue; // nb_nodes_per_element[nb_good_types] = Mesh::getNbNodesPerElement(type); // conn_val[nb_good_types] = mesh.getConnectivity(type, // _not_ghost).storage(); nb_element[nb_good_types] = // mesh.getConnectivity(type, _not_ghost).size(); // nb_good_types++; // } // AKANTU_DEBUG_ASSERT( // nb_good_types != 0, // "Some elements must be found in right dimension to compute facets!"); // /// array for the node-element list // node_to_elem.resizeRows(nb_nodes); // node_to_elem.clearRows(); // /// count number of occurrence of each node // for (UInt t = 0; t < nb_good_types; ++t) { // for (UInt el = 0; el < nb_element[t]; ++el) { // UInt el_offset = el * nb_nodes_per_element[t]; // for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) { // ++node_to_elem.rowOffset(conn_val[t][el_offset + n]); // } // } // } // node_to_elem.countToCSR(); // node_to_elem.resizeCols(); // node_to_elem.beginInsertions(); // /// rearrange element to get the node-element list // for (UInt t = 0, linearized_el = 0; t < nb_good_types; ++t) // for (UInt el = 0; el < nb_element[t]; ++el, ++linearized_el) { // UInt el_offset = el * nb_nodes_per_element[t]; // for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) // node_to_elem.insertInRow(conn_val[t][el_offset + n], linearized_el); // } // node_to_elem.endInsertions(); // delete[] conn_val; // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR<UInt> & node_to_elem, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, ghost_type).size(); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) ++node_to_elem.rowOffset(conn_val[el_offset + n]); } /// convert the occurrence array in a csr one node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { node_to_elem.insertInRow(conn_val[el_offset + n], el); } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { mesh.getConnectivity(*it, *gt).resize(0); // \todo inform the mesh event handler } } buildFacetsDimension(mesh, mesh, true, spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT( mesh_facets.isMeshFacets(), "The mesh_facets should be initialized with initMeshFacets"); /// generate facets buildFacetsDimension(mesh, mesh_facets, false, from_dimension); /// copy nodes type MeshAccessor mesh_accessor_facets(mesh_facets); mesh_accessor_facets.getNodesType().copy(mesh.getNodesType()); /// sort facets and generate sub-facets for (UInt i = from_dimension - 1; i > to_dimension; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension) { AKANTU_DEBUG_IN(); // save the current parent of mesh_facets and set it temporarly to mesh since // mesh is the one containing the elements for which mesh_facets has the // sub-elements // example: if the function is called with mesh = mesh_facets const Mesh * mesh_facets_parent = nullptr; try { mesh_facets_parent = &mesh_facets.getMeshParent(); } catch (...) { } mesh_facets.defineMeshParent(mesh); MeshAccessor mesh_accessor(mesh_facets); UInt spatial_dimension = mesh.getSpatialDimension(); const Array<Real> & mesh_facets_nodes = mesh_facets.getNodes(); - const Array<Real>::const_vector_iterator mesh_facets_nodes_it = + const auto mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); CSR<Element> node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array<UInt> counter; std::vector<Element> connected_elements; // init the SubelementToElement data to improve performance for (auto && ghost_type : ghost_types) { for (auto && type : mesh.elementTypes(dimension, ghost_type)) { mesh_accessor.getSubelementToElement(type, ghost_type); auto facet_types = mesh.getAllFacetTypes(type); for (auto && ft : arange(facet_types.size())) { auto facet_type = facet_types(ft); mesh_accessor.getElementToSubelement(facet_type, ghost_type); mesh_accessor.getConnectivity(facet_type, ghost_type); } } } const ElementSynchronizer * synchronizer = nullptr; if (mesh.isDistributed()) { synchronizer = &(mesh.getElementSynchronizer()); } Element current_element; for (auto && ghost_type : ghost_types) { GhostType facet_ghost_type = ghost_type; current_element.ghost_type = ghost_type; for (auto && type : mesh.elementTypes(dimension, ghost_type)) { auto facet_types = mesh.getAllFacetTypes(type); current_element.type = type; for (auto && ft : arange(facet_types.size())) { auto facet_type = facet_types(ft); auto nb_element = mesh.getNbElement(type, ghost_type); auto element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, ghost_type); auto connectivity_facets = &mesh_facets.getConnectivity(facet_type, ghost_type); auto nb_facet_per_element = mesh.getNbFacetsPerElement(type, ft); const auto & element_connectivity = mesh.getConnectivity(type, ghost_type); Matrix<const UInt> facet_local_connectivity( mesh.getFacetLocalConnectivity(type, ft)); auto nb_nodes_per_facet = connectivity_facets->getNbComponent(); Vector<UInt> facet(nb_nodes_per_facet); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; for (UInt f = 0; f < nb_facet_per_element; ++f) { for (UInt n = 0; n < nb_nodes_per_facet; ++n) facet(n) = element_connectivity(el, facet_local_connectivity(f, n)); UInt first_node_nb_elements = node_to_elem.getNbCols(facet(0)); counter.resize(first_node_nb_elements); counter.clear(); // loop over the other nodes to search intersecting elements, // which are the elements that share another node with the // starting element after first_node UInt local_el = 0; auto first_node_elements = node_to_elem.begin(facet(0)); auto first_node_elements_end = node_to_elem.end(facet(0)); for (; first_node_elements != first_node_elements_end; ++first_node_elements, ++local_el) { for (UInt n = 1; n < nb_nodes_per_facet; ++n) { auto node_elements_begin = node_to_elem.begin(facet(n)); auto node_elements_end = node_to_elem.end(facet(n)); counter(local_el) += std::count(node_elements_begin, node_elements_end, *first_node_elements); } } // counting the number of elements connected to the facets and // taking the minimum element number, because the facet should // be inserted just once UInt nb_element_connected_to_facet = 0; Element minimum_el = ElementNull; connected_elements.clear(); for (UInt el_f = 0; el_f < first_node_nb_elements; el_f++) { Element real_el = node_to_elem(facet(0), el_f); if (not(counter(el_f) == nb_nodes_per_facet - 1)) continue; ++nb_element_connected_to_facet; minimum_el = std::min(minimum_el, real_el); connected_elements.push_back(real_el); } if (minimum_el != current_element) continue; bool full_ghost_facet = false; UInt n = 0; while (n < nb_nodes_per_facet && mesh.isPureGhostNode(facet(n))) ++n; if (n == nb_nodes_per_facet) full_ghost_facet = true; if (full_ghost_facet) continue; if (boundary_only and nb_element_connected_to_facet != 1) continue; std::vector<Element> elements; // build elements_on_facets: linearized_el must come first // in order to store the facet in the correct direction // and avoid to invert the sign in the normal computation elements.push_back(current_element); if (nb_element_connected_to_facet == 1) { /// boundary facet elements.push_back(ElementNull); } else if (nb_element_connected_to_facet == 2) { /// internal facet elements.push_back(connected_elements[1]); /// check if facet is in between ghost and normal /// elements: if it's the case, the facet is either /// ghost or not ghost. The criterion to decide this /// is arbitrary. It was chosen to check the processor /// id (prank) of the two neighboring elements. If /// prank of the ghost element is lower than prank of /// the normal one, the facet is not ghost, otherwise /// it's ghost GhostType gt[2] = {_not_ghost, _not_ghost}; for (UInt el = 0; el < connected_elements.size(); ++el) gt[el] = connected_elements[el].ghost_type; if (gt[0] != gt[1] and (gt[0] == _not_ghost or gt[1] == _not_ghost)) { UInt prank[2]; for (UInt el = 0; el < 2; ++el) { prank[el] = synchronizer->getRank(connected_elements[el]); } // ugly trick from Marco detected :P bool ghost_one = (gt[0] != _ghost); if (prank[ghost_one] > prank[!ghost_one]) facet_ghost_type = _not_ghost; else facet_ghost_type = _ghost; connectivity_facets = &mesh_facets.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_facets.getElementToSubelement( facet_type, facet_ghost_type); } } else { /// facet of facet for (UInt i = 1; i < nb_element_connected_to_facet; ++i) { elements.push_back(connected_elements[i]); } } element_to_subelement->push_back(elements); connectivity_facets->push_back(facet); /// current facet index UInt current_facet = connectivity_facets->size() - 1; /// loop on every element connected to current facet and /// insert current facet in the first free spot of the /// subelement_to_element vector for (UInt elem = 0; elem < elements.size(); ++elem) { Element loc_el = elements[elem]; if (loc_el.type == _not_defined) continue; Array<Element> & subelement_to_element = mesh_facets.getSubelementToElement(loc_el.type, loc_el.ghost_type); UInt nb_facet_per_loc_element = subelement_to_element.getNbComponent(); for (UInt f_in = 0; f_in < nb_facet_per_loc_element; ++f_in) { auto & el = subelement_to_element(loc_el.element, f_in); if (el.type != _not_defined) continue; el.type = facet_type; el.element = current_facet; el.ghost_type = facet_ghost_type; break; } } /// reset connectivity in case a facet was found in /// between ghost and normal elements if (facet_ghost_type != ghost_type) { facet_ghost_type = ghost_type; connectivity_facets = &mesh_accessor.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_accessor.getElementToSubelement( facet_type, facet_ghost_type); } } } } } } // restore the parent of mesh_facet if (mesh_facets_parent) mesh_facets.defineMeshParent(*mesh_facets_parent); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, Array<UInt> & local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array<UInt> & old_nodes_numbers) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map<UInt, UInt> renumbering_map; for (UInt i = 0; i < old_nodes_numbers.size(); ++i) { renumbering_map[old_nodes_numbers(i)] = i; } /// renumber the nodes renumberNodesInConnectivity(local_connectivities, (nb_local_element + nb_ghost_element) * nb_nodes_per_element, renumbering_map); old_nodes_numbers.resize(renumbering_map.size()); for (auto & renumber_pair : renumbering_map) { old_nodes_numbers(renumber_pair.second) = renumber_pair.first; } renumbering_map.clear(); MeshAccessor mesh_accessor(mesh); /// copy the renumbered connectivity to the right place auto & local_conn = mesh_accessor.getConnectivity(type); local_conn.resize(nb_local_element); memcpy(local_conn.storage(), local_connectivities.storage(), nb_local_element * nb_nodes_per_element * sizeof(UInt)); auto & ghost_conn = mesh_accessor.getConnectivity(type, _ghost); ghost_conn.resize(nb_ghost_element); std::memcpy(ghost_conn.storage(), local_connectivities.storage() + nb_local_element * nb_nodes_per_element, nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); auto & ghost_counter = mesh_accessor.getGhostsCounters(type, _ghost); ghost_counter.resize(nb_ghost_element, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity( Array<UInt> & list_nodes, UInt nb_nodes, std::map<UInt, UInt> & renumbering_map) { AKANTU_DEBUG_IN(); UInt * connectivity = list_nodes.storage(); UInt new_node_num = renumbering_map.size(); for (UInt n = 0; n < nb_nodes; ++n, ++connectivity) { UInt & node = *connectivity; auto it = renumbering_map.find(node); if (it == renumbering_map.end()) { UInt old_node = node; renumbering_map[old_node] = new_node_num; node = new_node_num; ++new_node_num; } else { node = it->second; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::purifyMesh(Mesh & mesh) { AKANTU_DEBUG_IN(); std::map<UInt, UInt> renumbering_map; RemovedNodesEvent remove_nodes(mesh); Array<UInt> & nodes_removed = remove_nodes.getList(); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { auto ghost_type = (GhostType)gt; Mesh::type_iterator it = mesh.firstType(_all_dimensions, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != end; ++it) { ElementType type(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity.size()); renumberNodesInConnectivity( connectivity, nb_element * nb_nodes_per_element, renumbering_map); } } Array<UInt> & new_numbering = remove_nodes.getNewNumbering(); std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); auto it = renumbering_map.begin(); auto end = renumbering_map.end(); for (; it != end; ++it) { new_numbering(it->first) = it->second; } for (UInt i = 0; i < new_numbering.size(); ++i) { if (new_numbering(i) == UInt(-1)) nodes_removed.push_back(i); } mesh.sendEvent(remove_nodes); AKANTU_DEBUG_OUT(); } #if defined(AKANTU_COHESIVE_ELEMENT) /* -------------------------------------------------------------------------- */ UInt MeshUtils::insertCohesiveElements( Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion, Array<UInt> & doubled_nodes, Array<Element> & new_elements, bool only_double_facets) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt elements_to_insert = updateFacetToDouble(mesh_facets, facet_insertion); if (elements_to_insert > 0) { if (spatial_dimension == 1) { doublePointFacet(mesh, mesh_facets, doubled_nodes); } else { doubleFacet(mesh, mesh_facets, spatial_dimension - 1, doubled_nodes, true); findSubfacetToDouble<false>(mesh, mesh_facets); if (spatial_dimension == 2) { doubleSubfacet<2>(mesh, mesh_facets, doubled_nodes); } else if (spatial_dimension == 3) { doubleFacet(mesh, mesh_facets, 1, doubled_nodes, false); findSubfacetToDouble<true>(mesh, mesh_facets); doubleSubfacet<3>(mesh, mesh_facets, doubled_nodes); } } if (!only_double_facets) updateCohesiveData(mesh, mesh_facets, new_elements); } return elements_to_insert; } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doubleNodes(Mesh & mesh, const std::vector<UInt> & old_nodes, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); Array<Real> & position = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt old_nb_nodes = position.size(); UInt new_nb_nodes = old_nb_nodes + old_nodes.size(); UInt old_nb_doubled_nodes = doubled_nodes.size(); UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.size(); position.resize(new_nb_nodes); doubled_nodes.resize(new_nb_doubled_nodes); Array<Real>::iterator<Vector<Real>> position_begin = position.begin(spatial_dimension); for (UInt n = 0; n < old_nodes.size(); ++n) { UInt new_node = old_nb_nodes + n; /// store doubled nodes doubled_nodes(old_nb_doubled_nodes + n, 0) = old_nodes[n]; doubled_nodes(old_nb_doubled_nodes + n, 1) = new_node; /// update position std::copy(position_begin + old_nodes[n], position_begin + old_nodes[n] + 1, position_begin + new_node); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array<UInt> & doubled_nodes, bool facet_mode) { AKANTU_DEBUG_IN(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(facet_dimension, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(facet_dimension, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); const UInt nb_subfacet_per_facet = Mesh::getNbFacetsPerElement(type_facet); GhostType gt_subfacet = _casper; Array<std::vector<Element>> * f_to_subfacet = nullptr; Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); UInt nb_nodes_per_facet = conn_facet.getNbComponent(); UInt old_nb_facet = conn_facet.size(); UInt new_nb_facet = old_nb_facet + nb_facet_to_double; conn_facet.resize(new_nb_facet); subfacet_to_facet.resize(new_nb_facet); UInt new_facet = old_nb_facet - 1; Element new_facet_el{type_facet, 0, gt_facet}; Array<Element>::iterator<Vector<Element>> subfacet_to_facet_begin = subfacet_to_facet.begin(nb_subfacet_per_facet); Array<UInt>::iterator<Vector<UInt>> conn_facet_begin = conn_facet.begin(nb_nodes_per_facet); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); ++new_facet; /// adding a new facet by copying original one /// copy connectivity in new facet std::copy(conn_facet_begin + old_facet, conn_facet_begin + old_facet + 1, conn_facet_begin + new_facet); /// update subfacet_to_facet std::copy(subfacet_to_facet_begin + old_facet, subfacet_to_facet_begin + old_facet + 1, subfacet_to_facet_begin + new_facet); new_facet_el.element = new_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet_per_facet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; f_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, subfacet.ghost_type); } /// update facet_to_subfacet array (*f_to_subfacet)(subfacet.element).push_back(new_facet_el); } } /// update facet_to_subfacet and _segment_3 facets if any if (!facet_mode) { updateSubfacetToFacet(mesh_facets, type_facet, gt_facet, true); updateFacetToSubfacet(mesh_facets, type_facet, gt_facet, true); updateQuadraticSegments<true>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } else updateQuadraticSegments<false>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateFacetToDouble( Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); UInt nb_facets_to_double = 0.; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; const Array<bool> & f_insertion = facet_insertion(type_facet, gt_facet); Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); ElementType el_type = _not_defined; GhostType el_gt = _casper; UInt nb_facet_per_element = 0; Element old_facet_el{type_facet, 0, gt_facet}; Array<Element> * facet_to_element = nullptr; for (UInt f = 0; f < f_insertion.size(); ++f) { if (f_insertion(f) == false) continue; ++nb_facets_to_double; if (element_to_facet(f)[1].type == _not_defined #if defined(AKANTU_COHESIVE_ELEMENT) || element_to_facet(f)[1].kind() == _ek_cohesive #endif ) { AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary"); continue; } f_to_double.push_back(f); UInt new_facet = mesh_facets.getNbElement(type_facet, gt_facet) + f_to_double.size() - 1; old_facet_el.element = f; /// update facet_to_element vector Element & elem_to_update = element_to_facet(f)[1]; UInt el = elem_to_update.element; if (elem_to_update.ghost_type != el_gt || elem_to_update.type != el_type) { el_type = elem_to_update.type; el_gt = elem_to_update.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(el_type, el_gt); nb_facet_per_element = facet_to_element->getNbComponent(); } Element * f_update = std::find(facet_to_element->storage() + el * nb_facet_per_element, facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, old_facet_el); AKANTU_DEBUG_ASSERT( facet_to_element->storage() + el * nb_facet_per_element != facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, "Facet not found"); f_update->element = new_facet; /// update elements connected to facet std::vector<Element> first_facet_list = element_to_facet(f); element_to_facet.push_back(first_facet_list); /// set new and original facets as boundary facets element_to_facet(new_facet)[0] = element_to_facet(new_facet)[1]; element_to_facet(f)[1] = ElementNull; element_to_facet(new_facet)[1] = ElementNull; } } } AKANTU_DEBUG_OUT(); return nb_facets_to_double; } /* -------------------------------------------------------------------------- */ void MeshUtils::resetFacetToDouble(Mesh & mesh_facets) { AKANTU_DEBUG_IN(); for (UInt g = _not_ghost; g <= _ghost; ++g) { auto gt = (GhostType)g; Mesh::type_iterator it = mesh_facets.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh_facets.lastType(_all_dimensions, gt); for (; it != end; ++it) { ElementType type = *it; mesh_facets.getDataPointer<UInt>("facet_to_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "facets_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "elements_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "subfacets_to_subsubfacet_double", type, gt, 1, false); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool subsubfacet_mode> void MeshUtils::findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); GhostType gt_subfacet = _casper; ElementType type_subsubfacet = Mesh::getFacetType(type_subfacet); GhostType gt_subsubfacet = _casper; Array<UInt> * conn_subfacet = nullptr; Array<UInt> * sf_to_double = nullptr; Array<std::vector<Element>> * sf_to_subfacet_double = nullptr; Array<std::vector<Element>> * f_to_subfacet_double = nullptr; Array<std::vector<Element>> * el_to_subfacet_double = nullptr; UInt nb_subfacet = Mesh::getNbFacetsPerElement(type_facet); UInt nb_subsubfacet; UInt nb_nodes_per_sf_el; if (subsubfacet_mode) { nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subsubfacet); nb_subsubfacet = Mesh::getNbFacetsPerElement(type_subfacet); } else nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subfacet); Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array<Element> * subsubfacet_to_subfacet = nullptr; UInt old_nb_facet = subfacet_to_facet.size() - nb_facet_to_double; Element current_facet{type_facet, 0, gt_facet}; std::vector<Element> element_list; std::vector<Element> facet_list; std::vector<Element> * subfacet_list; if (subsubfacet_mode) subfacet_list = new std::vector<Element>; /// map to filter subfacets Array<std::vector<Element>> * facet_to_subfacet = nullptr; /// this is used to make sure that both new and old facets are /// checked UInt facets[2]; /// loop on every facet for (UInt f_index = 0; f_index < 2; ++f_index) { for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { facets[bool(f_index)] = f_to_double(facet); facets[!bool(f_index)] = old_nb_facet + facet; UInt old_facet = facets[0]; UInt new_facet = facets[1]; Element & starting_element = element_to_facet(new_facet)[0]; current_facet.element = old_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; if (subsubfacet_mode) { subsubfacet_to_subfacet = &mesh_facets.getSubelementToElement( type_subfacet, gt_subfacet); } else { conn_subfacet = &mesh_facets.getConnectivity(type_subfacet, gt_subfacet); sf_to_double = &mesh_facets.getData<UInt>( "facet_to_double", type_subfacet, gt_subfacet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subfacet, gt_subfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, gt_subfacet); } } if (subsubfacet_mode) { /// loop on every subsubfacet for (UInt ssf = 0; ssf < nb_subsubfacet; ++ssf) { Element & subsubfacet = (*subsubfacet_to_subfacet)(subfacet.element, ssf); if (subsubfacet == ElementNull) continue; if (gt_subsubfacet != subsubfacet.ghost_type) { gt_subsubfacet = subsubfacet.ghost_type; conn_subfacet = &mesh_facets.getConnectivity(type_subsubfacet, gt_subsubfacet); sf_to_double = &mesh_facets.getData<UInt>( "facet_to_double", type_subsubfacet, gt_subsubfacet); sf_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subsubfacet, gt_subsubfacet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subsubfacet, gt_subsubfacet); el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subsubfacet, gt_subsubfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subsubfacet, gt_subsubfacet); } UInt global_ssf = subsubfacet.element; Vector<UInt> subsubfacet_connectivity( conn_subfacet->storage() + global_ssf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subsubfacet is to be doubled if (findElementsAroundSubfacet<true>( mesh, mesh_facets, starting_element, current_facet, subsubfacet_connectivity, element_list, facet_list, subfacet_list) == false && removeElementsInVector(*subfacet_list, (*facet_to_subfacet)(global_ssf)) == false) { sf_to_double->push_back(global_ssf); sf_to_subfacet_double->push_back(*subfacet_list); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } else { const UInt global_sf = subfacet.element; Vector<UInt> subfacet_connectivity( conn_subfacet->storage() + global_sf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subfacet is to be doubled if (findElementsAroundSubfacet<false>( mesh, mesh_facets, starting_element, current_facet, subfacet_connectivity, element_list, facet_list) == false && removeElementsInVector( facet_list, (*facet_to_subfacet)(global_sf)) == false) { sf_to_double->push_back(global_sf); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } } } if (subsubfacet_mode) delete subfacet_list; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array<Element> & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; MeshAccessor mesh_facets_accessor(mesh_facets); for (auto gt_facet : ghost_types) { for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); auto & facet_to_coh_element = mesh_facets_accessor.getSubelementToElement(type_cohesive, gt_facet); auto & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); auto & conn_cohesive = mesh.getConnectivity(type_cohesive, gt_facet); UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); UInt old_nb_cohesive_elements = conn_cohesive.size(); UInt new_nb_cohesive_elements = conn_cohesive.size() + nb_facet_to_double; UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; facet_to_coh_element.resize(new_nb_cohesive_elements); conn_cohesive.resize(new_nb_cohesive_elements); UInt new_elements_old_size = new_elements.size(); new_elements.resize(new_elements_old_size + nb_facet_to_double); Element c_element{type_cohesive, 0, gt_facet}; Element f_element{type_facet, 0, gt_facet}; UInt facets[2]; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { /// (in 3D cohesive elements connectivity is inverted) facets[third_dimension] = f_to_double(facet); facets[!third_dimension] = old_nb_facet + facet; UInt cohesive_element = old_nb_cohesive_elements + facet; /// store doubled facets f_element.element = facets[0]; facet_to_coh_element(cohesive_element, 0) = f_element; f_element.element = facets[1]; facet_to_coh_element(cohesive_element, 1) = f_element; /// modify cohesive elements' connectivity for (UInt n = 0; n < nb_nodes_per_facet; ++n) { conn_cohesive(cohesive_element, n) = conn_facet(facets[0], n); conn_cohesive(cohesive_element, n + nb_nodes_per_facet) = conn_facet(facets[1], n); } /// update element_to_facet vectors c_element.element = cohesive_element; element_to_facet(facets[0])[1] = c_element; element_to_facet(facets[1])[1] = c_element; /// add cohesive element to the element event list new_elements(new_elements_old_size + facet) = c_element; } } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); if (spatial_dimension != 1) return; Array<Real> & position = mesh.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); const Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; UInt new_nb_facet = element_to_facet.size(); UInt old_nb_nodes = position.size(); UInt new_nb_nodes = old_nb_nodes + nb_facet_to_double; position.resize(new_nb_nodes); conn_facet.resize(new_nb_facet); UInt old_nb_doubled_nodes = doubled_nodes.size(); doubled_nodes.resize(old_nb_doubled_nodes + nb_facet_to_double); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt new_facet = old_nb_facet + facet; ElementType type = element_to_facet(new_facet)[0].type; UInt el = element_to_facet(new_facet)[0].element; GhostType gt = element_to_facet(new_facet)[0].ghost_type; UInt old_node = conn_facet(old_facet); UInt new_node = old_nb_nodes + facet; /// update position position(new_node) = position(old_node); conn_facet(new_facet) = new_node; Array<UInt> & conn_segment = mesh.getConnectivity(type, gt); UInt nb_nodes_per_segment = conn_segment.getNbComponent(); /// update facet connectivity UInt i; for (i = 0; conn_segment(el, i) != old_node && i <= nb_nodes_per_segment; ++i) ; conn_segment(el, i) = new_node; doubled_nodes(old_nb_doubled_nodes + facet, 0) = old_node; doubled_nodes(old_nb_doubled_nodes + facet, 1) = new_node; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_segments> void MeshUtils::updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (type_facet != _segment_3) return; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); UInt old_nb_facet = mesh_facets.getNbElement(type_facet, gt_facet) - nb_facet_to_double; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); /// this ones matter only for segments in 3D Array<std::vector<Element>> * el_to_subfacet_double = nullptr; Array<std::vector<Element>> * f_to_subfacet_double = nullptr; if (third_dim_segments) { el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_facet, gt_facet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_facet, gt_facet); } std::vector<UInt> middle_nodes; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt node = conn_facet(old_facet, 2); if (!mesh.isPureGhostNode(node)) middle_nodes.push_back(node); } UInt n = doubled_nodes.size(); doubleNodes(mesh, middle_nodes, doubled_nodes); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt old_node = conn_facet(old_facet, 2); if (mesh.isPureGhostNode(old_node)) continue; UInt new_node = doubled_nodes(n, 1); UInt new_facet = old_nb_facet + facet; conn_facet(new_facet, 2) = new_node; if (third_dim_segments) { updateElementalConnectivity(mesh_facets, old_node, new_node, element_to_facet(new_facet)); updateElementalConnectivity(mesh, old_node, new_node, (*el_to_subfacet_double)(facet), &(*f_to_subfacet_double)(facet)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_facet(new_facet)); } ++n; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); /// update subfacet_to_facet vector ElementType type_facet = _not_defined; GhostType gt_facet = _casper; Array<Element> * subfacet_to_facet = nullptr; UInt nb_subfacet_per_facet = 0; UInt old_nb_subfacet = mesh_facets.getNbElement(type_subfacet, gt_subfacet) - nb_subfacet_to_double; Array<std::vector<Element>> * facet_list = nullptr; if (facet_mode) facet_list = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); else facet_list = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); Element old_subfacet_el{type_subfacet, 0, gt_subfacet}; Element new_subfacet_el{type_subfacet, 0, gt_subfacet}; for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { old_subfacet_el.element = sf_to_double(sf); new_subfacet_el.element = old_nb_subfacet + sf; for (UInt f = 0; f < (*facet_list)(sf).size(); ++f) { Element & facet = (*facet_list)(sf)[f]; if (facet.type != type_facet || facet.ghost_type != gt_facet) { type_facet = facet.type; gt_facet = facet.ghost_type; subfacet_to_facet = &mesh_facets.getSubelementToElement(type_facet, gt_facet); nb_subfacet_per_facet = subfacet_to_facet->getNbComponent(); } Element * sf_update = std::find( subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet, subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, old_subfacet_el); AKANTU_DEBUG_ASSERT(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet != subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, "Subfacet not found"); *sf_update = new_subfacet_el; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); Array<std::vector<Element>> & facet_to_subfacet = mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); Array<std::vector<Element>> * facet_to_subfacet_double = nullptr; if (facet_mode) { facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); } else { facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); } UInt old_nb_subfacet = facet_to_subfacet.size(); facet_to_subfacet.resize(old_nb_subfacet + nb_subfacet_to_double); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) facet_to_subfacet(old_nb_subfacet + sf) = (*facet_to_subfacet_double)(sf); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MeshUtils::doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_subfacet = *gt; Mesh::type_iterator it = mesh_facets.firstType(0, gt_subfacet); Mesh::type_iterator end = mesh_facets.lastType(0, gt_subfacet); for (; it != end; ++it) { ElementType type_subfacet = *it; Array<UInt> & sf_to_double = mesh_facets.getData<UInt>( "facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); if (nb_subfacet_to_double == 0) continue; AKANTU_DEBUG_ASSERT( type_subfacet == _point_1, "Only _point_1 subfacet doubling is supported at the moment"); Array<UInt> & conn_subfacet = mesh_facets.getConnectivity(type_subfacet, gt_subfacet); UInt old_nb_subfacet = conn_subfacet.size(); UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double; conn_subfacet.resize(new_nb_subfacet); std::vector<UInt> nodes_to_double; UInt old_nb_doubled_nodes = doubled_nodes.size(); /// double nodes for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_subfacet = sf_to_double(sf); nodes_to_double.push_back(conn_subfacet(old_subfacet)); } doubleNodes(mesh, nodes_to_double, doubled_nodes); /// add new nodes in connectivity for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt new_subfacet = old_nb_subfacet + sf; UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); conn_subfacet(new_subfacet) = new_node; } /// update facet and element connectivity Array<std::vector<Element>> & f_to_subfacet_double = mesh_facets.getData<std::vector<Element>>("facets_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element>> & el_to_subfacet_double = mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element>> * sf_to_subfacet_double = nullptr; if (spatial_dimension == 3) sf_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_node = doubled_nodes(old_nb_doubled_nodes + sf, 0); UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); updateElementalConnectivity(mesh, old_node, new_node, el_to_subfacet_double(sf), &f_to_subfacet_double(sf)); updateElementalConnectivity(mesh_facets, old_node, new_node, f_to_subfacet_double(sf)); if (spatial_dimension == 3) updateElementalConnectivity(mesh_facets, old_node, new_node, (*sf_to_subfacet_double)(sf)); } if (spatial_dimension == 2) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, true); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, true); } else if (spatial_dimension == 3) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, false); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::flipFacets( Mesh & mesh_facets, const ElementTypeMapArray<UInt> & global_connectivity, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); /// get global connectivity for local mesh ElementTypeMapArray<UInt> global_connectivity_tmp("global_connectivity_tmp", mesh_facets.getID(), mesh_facets.getMemoryID()); global_connectivity_tmp.initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _ghost_type = gt_facet, _with_nb_nodes_per_element = true, _with_nb_element = true); mesh_facets.getGlobalConnectivity(global_connectivity_tmp); /// loop on every facet for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { auto & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet); const auto & g_connectivity = global_connectivity(type_facet, gt_facet); auto & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet); auto & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); UInt nb_subfacet_per_facet = subfacet_to_facet.getNbComponent(); UInt nb_nodes_per_facet = connectivity.getNbComponent(); UInt nb_facet = connectivity.size(); UInt nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); auto & global_conn_tmp = global_connectivity_tmp(type_facet, gt_facet); auto conn_it = connectivity.begin(nb_nodes_per_facet); auto gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet); auto conn_glob_it = g_connectivity.begin(nb_nodes_per_facet); auto subf_to_f = subfacet_to_facet.begin(nb_subfacet_per_facet); auto * conn_tmp_pointer = new UInt[nb_nodes_per_facet]; Vector<UInt> conn_tmp(conn_tmp_pointer, nb_nodes_per_facet); Element el_tmp; auto * subf_tmp_pointer = new Element[nb_subfacet_per_facet]; Vector<Element> subf_tmp(subf_tmp_pointer, nb_subfacet_per_facet); for (UInt f = 0; f < nb_facet; ++f, ++conn_it, ++gconn_tmp_it, ++subf_to_f, ++conn_glob_it) { Vector<UInt> & gconn_tmp = *gconn_tmp_it; const Vector<UInt> & conn_glob = *conn_glob_it; Vector<UInt> & conn_local = *conn_it; /// skip facet if connectivities are the same if (gconn_tmp == conn_glob) continue; /// re-arrange connectivity conn_tmp = conn_local; UInt * begin = conn_glob.storage(); UInt * end = conn_glob.storage() + nb_nodes_per_facet; for (UInt n = 0; n < nb_nodes_per_facet; ++n) { UInt * new_node = std::find(begin, end, gconn_tmp(n)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; conn_local(new_position) = conn_tmp(n); } /// if 3D, check if facets are just rotated if (spatial_dimension == 3) { /// find first node UInt * new_node = std::find(begin, end, gconn_tmp(0)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; UInt n = 1; /// count how many nodes in the received connectivity follow /// the same order of those in the local connectivity for (; n < nb_nodes_per_P1_facet && gconn_tmp(n) == conn_glob((new_position + n) % nb_nodes_per_P1_facet); ++n) ; /// skip the facet inversion if facet is just rotated if (n == nb_nodes_per_P1_facet) continue; } /// update data to invert facet el_tmp = el_to_f(f)[0]; el_to_f(f)[0] = el_to_f(f)[1]; el_to_f(f)[1] = el_tmp; subf_tmp = (*subf_to_f); (*subf_to_f)(0) = subf_tmp(1); (*subf_to_f)(1) = subf_tmp(0); } delete[] subf_tmp_pointer; delete[] conn_tmp_pointer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::fillElementToSubElementsData(Mesh & mesh) { AKANTU_DEBUG_IN(); if (mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) { AKANTU_DEBUG_INFO("There are not facets, add them in the mesh file or call " "the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray<Real> barycenters("barycenter_tmp", mesh.getID(), mesh.getMemoryID()); barycenters.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = _all_dimensions); // mesh.initElementTypeMapArray(barycenters, spatial_dimension, // _all_dimensions); Element element; for (auto ghost_type : ghost_types) { element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(_all_dimensions, ghost_type)) { element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array<Real> & barycenters_arr = barycenters(type, ghost_type); barycenters_arr.resize(nb_element); auto bary = barycenters_arr.begin(spatial_dimension); auto bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { element.element = el; mesh.getBarycenter(element, *bary); } } } MeshAccessor mesh_accessor(mesh); for (Int sp(spatial_dimension); sp >= 1; --sp) { if (mesh.getNbElement(sp) == 0) continue; for (auto ghost_type : ghost_types) { for (auto & type : mesh.elementTypes(sp, ghost_type)) { mesh_accessor.getSubelementToElement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh_accessor.getSubelementToElement(type, ghost_type).clear(); } for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { mesh_accessor.getElementToSubelement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh.getElementToSubelement(type, ghost_type).clear(); } } CSR<Element> nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (auto ghost_type : ghost_types) { facet_element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { facet_element.type = type; auto & element_to_subelement = mesh.getElementToSubelement(type, ghost_type); const auto & connectivity = mesh.getConnectivity(type, ghost_type); auto fit = connectivity.begin(mesh.getNbNodesPerElement(type)); auto fend = connectivity.end(mesh.getNbNodesPerElement(type)); UInt fid = 0; for (; fit != fend; ++fit, ++fid) { const Vector<UInt> & facet = *fit; facet_element.element = fid; std::map<Element, UInt> element_seen_counter; UInt nb_nodes_per_facet = mesh.getNbNodesPerElement(Mesh::getP1ElementType(type)); for (UInt n(0); n < nb_nodes_per_facet; ++n) { auto eit = nodes_to_elements.begin(facet(n)); auto eend = nodes_to_elements.end(facet(n)); for (; eit != eend; ++eit) { auto & elem = *eit; auto cit = element_seen_counter.find(elem); if (cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } std::vector<Element> connected_elements; auto cit = element_seen_counter.begin(); auto cend = element_seen_counter.end(); for (; cit != cend; ++cit) { if (cit->second == nb_nodes_per_facet) connected_elements.push_back(cit->first); } auto ceit = connected_elements.begin(); auto ceend = connected_elements.end(); for (; ceit != ceend; ++ceit) element_to_subelement(fid).push_back(*ceit); for (UInt ce = 0; ce < connected_elements.size(); ++ce) { Element & elem = connected_elements[ce]; Array<Element> & subelement_to_element = mesh_accessor.getSubelementToElement(elem.type, elem.ghost_type); UInt f(0); for (; f < mesh.getNbFacetsPerElement(elem.type) && subelement_to_element(elem.element, f) != ElementNull; ++f) ; AKANTU_DEBUG_ASSERT( f < mesh.getNbFacetsPerElement(elem.type), "The element " << elem << " seems to have too many facets!! (" << f << " < " << mesh.getNbFacetsPerElement(elem.type) << ")"); subelement_to_element(elem.element, f) = facet_element; } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_points> bool MeshUtils::findElementsAroundSubfacet( const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector<UInt> & subfacet_connectivity, std::vector<Element> & elem_list, std::vector<Element> & facet_list, std::vector<Element> * subfacet_list) { AKANTU_DEBUG_IN(); /// preallocated stuff before starting bool facet_matched = false; elem_list.clear(); facet_list.clear(); if (third_dim_points) subfacet_list->clear(); elem_list.push_back(starting_element); const Array<UInt> * facet_connectivity = nullptr; const Array<UInt> * sf_connectivity = nullptr; const Array<Element> * facet_to_element = nullptr; const Array<Element> * subfacet_to_facet = nullptr; ElementType current_type = _not_defined; GhostType current_ghost_type = _casper; ElementType current_facet_type = _not_defined; GhostType current_facet_ghost_type = _casper; ElementType current_subfacet_type = _not_defined; GhostType current_subfacet_ghost_type = _casper; const Array<std::vector<Element>> * element_to_facet = nullptr; const Element * opposing_el = nullptr; std::queue<Element> elements_to_check; elements_to_check.push(starting_element); /// keep going until there are elements to check while (!elements_to_check.empty()) { /// check current element Element & current_el = elements_to_check.front(); if (current_el.type != current_type || current_el.ghost_type != current_ghost_type) { current_type = current_el.type; current_ghost_type = current_el.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(current_type, current_ghost_type); } /// loop over each facet of the element for (UInt f = 0; f < facet_to_element->getNbComponent(); ++f) { const Element & current_facet = (*facet_to_element)(current_el.element, f); if (current_facet == ElementNull) continue; if (current_facet_type != current_facet.type || current_facet_ghost_type != current_facet.ghost_type) { current_facet_type = current_facet.type; current_facet_ghost_type = current_facet.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( current_facet_type, current_facet_ghost_type); facet_connectivity = &mesh_facets.getConnectivity( current_facet_type, current_facet_ghost_type); if (third_dim_points) subfacet_to_facet = &mesh_facets.getSubelementToElement( current_facet_type, current_facet_ghost_type); } /// check if end facet is reached if (current_facet == end_facet) facet_matched = true; /// add this facet if not already passed if (std::find(facet_list.begin(), facet_list.end(), current_facet) == facet_list.end() && hasElement(*facet_connectivity, current_facet, subfacet_connectivity)) { facet_list.push_back(current_facet); if (third_dim_points) { /// check subfacets for (UInt sf = 0; sf < subfacet_to_facet->getNbComponent(); ++sf) { const Element & current_subfacet = (*subfacet_to_facet)(current_facet.element, sf); if (current_subfacet == ElementNull) continue; if (current_subfacet_type != current_subfacet.type || current_subfacet_ghost_type != current_subfacet.ghost_type) { current_subfacet_type = current_subfacet.type; current_subfacet_ghost_type = current_subfacet.ghost_type; sf_connectivity = &mesh_facets.getConnectivity( current_subfacet_type, current_subfacet_ghost_type); } if (std::find(subfacet_list->begin(), subfacet_list->end(), current_subfacet) == subfacet_list->end() && hasElement(*sf_connectivity, current_subfacet, subfacet_connectivity)) subfacet_list->push_back(current_subfacet); } } } else continue; /// consider opposing element if ((*element_to_facet)(current_facet.element)[0] == current_el) opposing_el = &(*element_to_facet)(current_facet.element)[1]; else opposing_el = &(*element_to_facet)(current_facet.element)[0]; /// skip null elements since they are on a boundary if (*opposing_el == ElementNull) continue; /// skip this element if already added if (std::find(elem_list.begin(), elem_list.end(), *opposing_el) != elem_list.end()) continue; /// only regular elements have to be checked if (opposing_el->kind() == _ek_regular) elements_to_check.push(*opposing_el); elem_list.push_back(*opposing_el); #ifndef AKANTU_NDEBUG const Array<UInt> & conn_elem = mesh.getConnectivity(opposing_el->type, opposing_el->ghost_type); AKANTU_DEBUG_ASSERT( hasElement(conn_elem, *opposing_el, subfacet_connectivity), "Subfacet doesn't belong to this element"); #endif } /// erased checked element from the list elements_to_check.pop(); } AKANTU_DEBUG_OUT(); return facet_matched; } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateLocalMasterGlobalConnectivity(Mesh & mesh, UInt local_nb_new_nodes) { const auto & comm = mesh.getCommunicator(); Int rank = comm.whoAmI(); Int nb_proc = comm.getNbProc(); if (nb_proc == 1) return local_nb_new_nodes; /// resize global ids array Array<UInt> & nodes_global_ids = mesh.getGlobalNodesIds(); UInt old_nb_nodes = mesh.getNbNodes() - local_nb_new_nodes; nodes_global_ids.resize(mesh.getNbNodes()); /// compute the number of global nodes based on the number of old nodes Vector<UInt> old_local_master_nodes(nb_proc); for (UInt n = 0; n < old_nb_nodes; ++n) if (mesh.isLocalOrMasterNode(n)) ++old_local_master_nodes(rank); comm.allGather(old_local_master_nodes); UInt old_global_nodes = std::accumulate(old_local_master_nodes.storage(), old_local_master_nodes.storage() + nb_proc, 0); /// compute amount of local or master doubled nodes Vector<UInt> local_master_nodes(nb_proc); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) if (mesh.isLocalOrMasterNode(n)) ++local_master_nodes(rank); comm.allGather(local_master_nodes); /// update global number of nodes UInt total_nb_new_nodes = std::accumulate( local_master_nodes.storage(), local_master_nodes.storage() + nb_proc, 0); if (total_nb_new_nodes == 0) return 0; /// set global ids of local and master nodes UInt starting_index = std::accumulate(local_master_nodes.storage(), local_master_nodes.storage() + rank, old_global_nodes); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) { nodes_global_ids(n) = starting_index; ++starting_index; } } MeshAccessor mesh_accessor(mesh); mesh_accessor.setNbGlobalNodes(old_global_nodes + total_nb_new_nodes); return total_nb_new_nodes; } /* -------------------------------------------------------------------------- */ void MeshUtils::updateElementalConnectivity( Mesh & mesh, UInt old_node, UInt new_node, const std::vector<Element> & element_list, __attribute__((unused)) const std::vector<Element> * facet_list) { AKANTU_DEBUG_IN(); ElementType el_type = _not_defined; GhostType gt_type = _casper; Array<UInt> * conn_elem = nullptr; #if defined(AKANTU_COHESIVE_ELEMENT) const Array<Element> * cohesive_facets = nullptr; #endif UInt nb_nodes_per_element = 0; UInt * n_update = nullptr; for (UInt el = 0; el < element_list.size(); ++el) { const Element & elem = element_list[el]; if (elem.type == _not_defined) continue; if (elem.type != el_type || elem.ghost_type != gt_type) { el_type = elem.type; gt_type = elem.ghost_type; conn_elem = &mesh.getConnectivity(el_type, gt_type); nb_nodes_per_element = conn_elem->getNbComponent(); #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind() == _ek_cohesive) cohesive_facets = &mesh.getMeshFacets().getSubelementToElement(el_type, gt_type); #endif } #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind() == _ek_cohesive) { AKANTU_DEBUG_ASSERT( facet_list != nullptr, "Provide a facet list in order to update cohesive elements"); /// loop over cohesive element's facets for (UInt f = 0, n = 0; f < 2; ++f, n += nb_nodes_per_element / 2) { const Element & facet = (*cohesive_facets)(elem.element, f); /// skip facets if not present in the list if (std::find(facet_list->begin(), facet_list->end(), facet) == facet_list->end()) continue; n_update = std::find( conn_elem->storage() + elem.element * nb_nodes_per_element + n, conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, "Node not found in current element"); /// update connectivity *n_update = new_node; } } else { #endif n_update = std::find(conn_elem->storage() + elem.element * nb_nodes_per_element, conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, "Node not found in current element"); /// update connectivity *n_update = new_node; #if defined(AKANTU_COHESIVE_ELEMENT) } #endif } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/mesh_utils/mesh_utils_pbc.cc b/src/mesh_utils/mesh_utils_pbc.cc index efbe22315..5e011b23d 100644 --- a/src/mesh_utils/mesh_utils_pbc.cc +++ b/src/mesh_utils/mesh_utils_pbc.cc @@ -1,298 +1,298 @@ /** * @file mesh_utils_pbc.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Wed Feb 09 2011 * @date last modification: Tue Sep 15 2015 * * @brief periodic boundary condition connectivity tweak * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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 <map> /* -------------------------------------------------------------------------- */ #include "element_group.hh" #include "mesh_accessor.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /// class that sorts a set of nodes of same coordinates in 'dir' direction class CoordinatesComparison { public: CoordinatesComparison(const UInt dimension, const UInt dir_1, const UInt dir_2, Real normalization, Real tolerance, const Array<Real> & coords) : dim(dimension), dir_1(dir_1), dir_2(dir_2), normalization(normalization), tolerance(tolerance), coords_it(coords.begin(dim)) {} // answers the question whether n2 is larger or equal to n1 bool operator()(const UInt n1, const UInt n2) { Vector<Real> coords_n1 = coords_it[n1]; Vector<Real> coords_n2 = coords_it[n2]; return this->operator()(coords_n1, coords_n2); } bool operator()(const Vector<Real> & coords_n1, const Vector<Real> & coords_n2) { Real diff = coords_n1(dir_1) - coords_n2(dir_1);; if (dim == 2 || std::abs(diff) / normalization > tolerance) return diff > 0. ? false : true; else if (dim > 2) { diff = coords_n1(dir_2) - coords_n2(dir_2);; return diff > 0 ? false : true; } return true; } private: UInt dim; UInt dir_1; UInt dir_2; Real normalization; Real tolerance; const Array<Real>::const_vector_iterator coords_it; }; /* -------------------------------------------------------------------------- */ void MeshUtils::computePBCMap(const Mesh & mesh, const UInt dir, std::map<UInt, UInt> & pbc_pair) { Array<UInt> selected_left; Array<UInt> selected_right; const UInt dim = mesh.getSpatialDimension(); - Array<Real>::const_vector_iterator it = mesh.getNodes().begin(dim); - Array<Real>::const_vector_iterator end = mesh.getNodes().end(dim); + auto it = mesh.getNodes().begin(dim); + auto end = mesh.getNodes().end(dim); if (dim <= dir) return; const Vector<Real> & lower_bounds = mesh.getLowerBounds(); const Vector<Real> & upper_bounds = mesh.getUpperBounds(); AKANTU_DEBUG_INFO("min " << lower_bounds(dir)); AKANTU_DEBUG_INFO("max " << upper_bounds(dir)); for (UInt node = 0; it != end; ++it, ++node) { const Vector<Real> & coords = *it; AKANTU_DEBUG_TRACE("treating " << coords(dir)); if (Math::are_float_equal(coords(dir), lower_bounds(dir))) { AKANTU_DEBUG_TRACE("pushing node " << node << " on the left side"); selected_left.push_back(node); } else if (Math::are_float_equal(coords(dir), upper_bounds(dir))) { selected_right.push_back(node); AKANTU_DEBUG_TRACE("pushing node " << node << " on the right side"); } } AKANTU_DEBUG_INFO( "found " << selected_left.size() << " and " << selected_right.size() << " nodes at each boundary for direction " << dir); // match pairs MeshUtils::matchPBCPairs(mesh, dir, selected_left, selected_right, pbc_pair); } /* -------------------------------------------------------------------------- */ void MeshUtils::computePBCMap(const Mesh & mesh, const std::pair<ID, ID> & surface_pair, std::map<UInt, UInt> & pbc_pair) { Array<UInt> selected_first; Array<UInt> selected_second; // find nodes on surfaces const ElementGroup & first_surf = mesh.getElementGroup(surface_pair.first); const ElementGroup & second_surf = mesh.getElementGroup(surface_pair.second); // if this surface pair is not on this proc if (first_surf.getNbNodes() == 0 || second_surf.getNbNodes() == 0) { AKANTU_DEBUG_WARNING("computePBCMap has at least one surface without any " "nodes. I will ignore it."); return; } // copy nodes from element group selected_first.copy(first_surf.getNodeGroup().getNodes()); selected_second.copy(second_surf.getNodeGroup().getNodes()); // coordinates const Array<Real> & coords = mesh.getNodes(); const UInt dim = mesh.getSpatialDimension(); // variables to find min and max of surfaces Real first_max[3], first_min[3]; Real second_max[3], second_min[3]; for (UInt i = 0; i < dim; ++i) { first_min[i] = std::numeric_limits<Real>::max(); second_min[i] = std::numeric_limits<Real>::max(); first_max[i] = -std::numeric_limits<Real>::max(); second_max[i] = -std::numeric_limits<Real>::max(); } // find min and max of surface nodes - for (Array<UInt>::scalar_iterator it = selected_first.begin(); + for (auto it = selected_first.begin(); it != selected_first.end(); ++it) { for (UInt i = 0; i < dim; ++i) { if (first_min[i] > coords(*it, i)) first_min[i] = coords(*it, i); if (first_max[i] < coords(*it, i)) first_max[i] = coords(*it, i); } } - for (Array<UInt>::scalar_iterator it = selected_second.begin(); + for (auto it = selected_second.begin(); it != selected_second.end(); ++it) { for (UInt i = 0; i < dim; ++i) { if (second_min[i] > coords(*it, i)) second_min[i] = coords(*it, i); if (second_max[i] < coords(*it, i)) second_max[i] = coords(*it, i); } } // find direction of pbc Int first_dir = -1; #ifndef AKANTU_NDEBUG Int second_dir = -2; #endif for (UInt i = 0; i < dim; ++i) { if (Math::are_float_equal(first_min[i], first_max[i])) { first_dir = i; } #ifndef AKANTU_NDEBUG if (Math::are_float_equal(second_min[i], second_max[i])) { second_dir = i; } #endif } AKANTU_DEBUG_ASSERT(first_dir == second_dir, "Surface pair has not same direction. Surface " << surface_pair.first << " dir=" << first_dir << " ; Surface " << surface_pair.second << " dir=" << second_dir); UInt dir = first_dir; // match pairs if (first_min[dir] < second_min[dir]) MeshUtils::matchPBCPairs(mesh, dir, selected_first, selected_second, pbc_pair); else MeshUtils::matchPBCPairs(mesh, dir, selected_second, selected_first, pbc_pair); } /* -------------------------------------------------------------------------- */ void MeshUtils::matchPBCPairs(const Mesh & mesh, const UInt dir, Array<UInt> & selected_left, Array<UInt> & selected_right, std::map<UInt, UInt> & pbc_pair) { // tolerance is that large because most meshers generate points coordinates // with single precision only (it is the case of GMSH for instance) Real tolerance = 1e-7; const UInt dim = mesh.getSpatialDimension(); Real normalization = mesh.getUpperBounds()(dir) - mesh.getLowerBounds()(dir); AKANTU_DEBUG_ASSERT(std::abs(normalization) > Math::getTolerance(), "In matchPBCPairs: The normalization is zero. " << "Did you compute the bounding box of the mesh?"); auto odir_1 = UInt(-1), odir_2 = UInt(-1); if (dim == 3) { if (dir == _x) { odir_1 = _y; odir_2 = _z; } else if (dir == _y) { odir_1 = _x; odir_2 = _z; } else if (dir == _z) { odir_1 = _x; odir_2 = _y; } } else if (dim == 2) { if (dir == _x) { odir_1 = _y; } else if (dir == _y) { odir_1 = _x; } } CoordinatesComparison compare_nodes(dim, odir_1, odir_2, normalization, tolerance, mesh.getNodes()); std::sort(selected_left.begin(), selected_left.end(), compare_nodes); std::sort(selected_right.begin(), selected_right.end(), compare_nodes); - Array<UInt>::scalar_iterator it_left = selected_left.begin(); - Array<UInt>::scalar_iterator end_left = selected_left.end(); + auto it_left = selected_left.begin(); + auto end_left = selected_left.end(); - Array<UInt>::scalar_iterator it_right = selected_right.begin(); - Array<UInt>::scalar_iterator end_right = selected_right.end(); + auto it_right = selected_right.begin(); + auto end_right = selected_right.end(); - Array<Real>::const_vector_iterator nit = mesh.getNodes().begin(dim); + auto nit = mesh.getNodes().begin(dim); while ((it_left != end_left) && (it_right != end_right)) { UInt i1 = *it_left; UInt i2 = *it_right; Vector<Real> coords1 = nit[i1]; Vector<Real> coords2 = nit[i2]; AKANTU_DEBUG_TRACE("do I pair? " << i1 << "(" << coords1 << ") with" << i2 << "(" << coords2 << ") in direction " << dir); Real dx = 0.0; Real dy = 0.0; if (dim >= 2) dx = coords1(odir_1) - coords2(odir_1); if (dim == 3) dy = coords1(odir_2) - coords2(odir_2); if (std::abs(dx * dx + dy * dy) / normalization < tolerance) { // then i match these pairs if (pbc_pair.count(i2)) { i2 = pbc_pair[i2]; } pbc_pair[i1] = i2; AKANTU_DEBUG_TRACE("pairing " << i1 << "(" << coords1 << ") with" << i2 << "(" << coords2 << ") in direction " << dir); ++it_left; ++it_right; } else if (compare_nodes(coords1, coords2)) { ++it_left; } else { ++it_right; } } AKANTU_DEBUG_INFO("found " << pbc_pair.size() << " pairs for direction " << dir); } } // akantu diff --git a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc index 4086bae8e..e5496fd7e 100644 --- a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc +++ b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc @@ -1,310 +1,310 @@ /** * @file neighborhood_max_criterion.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Thu Oct 15 2015 * @date last modification: Tue Nov 24 2015 * * @brief Implementation of class NeighborhoodMaxCriterion * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "neighborhood_max_criterion.hh" #include "grid_synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NeighborhoodMaxCriterion::NeighborhoodMaxCriterion( Model & model, const ElementTypeMapReal & quad_coordinates, const ID & criterion_id, const ID & id, const MemoryID & memory_id) : NeighborhoodBase(model, quad_coordinates, id, memory_id), Parsable(ParserType::_non_local, id), is_highest("is_highest", id, memory_id), criterion(criterion_id, id, memory_id) { AKANTU_DEBUG_IN(); this->registerParam("radius", neighborhood_radius, 100., _pat_parsable | _pat_readable, "Non local radius"); Mesh & mesh = this->model.getMesh(); /// allocate the element type map arrays for _not_ghosts: One entry per quad GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { UInt new_size = this->quad_coordinates(*it, ghost_type).size(); this->is_highest.alloc(new_size, 1, *it, ghost_type, true); this->criterion.alloc(new_size, 1, *it, ghost_type, true); } /// criterion needs allocation also for ghost ghost_type = _ghost; it = mesh.firstType(spatial_dimension, ghost_type); last_type = mesh.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { UInt new_size = this->quad_coordinates(*it, ghost_type).size(); this->criterion.alloc(new_size, 1, *it, ghost_type, true); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NeighborhoodMaxCriterion::~NeighborhoodMaxCriterion() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::initNeighborhood() { AKANTU_DEBUG_IN(); /// parse the input parameter const Parser & parser = getStaticParser(); const ParserSection & section_neighborhood = *(parser.getSubSections(ParserType::_neighborhood).first); this->parseSection(section_neighborhood); AKANTU_DEBUG_INFO("Creating the grid"); this->createGrid(); /// insert the non-ghost quads into the grid this->insertAllQuads(_not_ghost); /// store the number of current ghost elements for each type in the mesh ElementTypeMap<UInt> nb_ghost_protected; Mesh & mesh = this->model.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); for (; it != last_type; ++it) nb_ghost_protected(mesh.getNbElement(*it, _ghost), *it, _ghost); /// create the grid synchronizer this->createGridSynchronizer(); /// insert the ghost quads into the grid this->insertAllQuads(_ghost); /// create the pair lists this->updatePairList(); /// remove the unneccessary ghosts this->cleanupExtraGhostElements(nb_ghost_protected); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::createGridSynchronizer() { this->is_creating_grid = true; std::set<SynchronizationTag> tags; tags.insert(_gst_nh_criterion); std::stringstream sstr; sstr << getID() << ":grid_synchronizer"; this->grid_synchronizer = std::make_unique<GridSynchronizer>( this->model.getMesh(), *spatial_grid, * this, tags, sstr.str(), 0, false); this->is_creating_grid = false; } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::insertAllQuads(const GhostType & ghost_type) { IntegrationPoint q; q.ghost_type = ghost_type; Mesh & mesh = this->model.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); UInt nb_quad = this->model.getFEEngine().getNbIntegrationPoints(*it, ghost_type); const Array<Real> & quads = this->quad_coordinates(*it, ghost_type); q.type = *it; - Array<Real>::const_vector_iterator quad = quads.begin(spatial_dimension); + auto quad = quads.begin(spatial_dimension); for (UInt e = 0; e < nb_element; ++e) { q.element = e; for (UInt nq = 0; nq < nb_quad; ++nq) { q.num_point = nq; q.global_num = q.element * nb_quad + nq; spatial_grid->insert(q, *quad); ++quad; } } } } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::findMaxQuads( std::vector<IntegrationPoint> & max_quads) { AKANTU_DEBUG_IN(); /// clear the element type maps this->is_highest.clear(); this->criterion.clear(); /// update the values of the criterion this->model.updateDataForNonLocalCriterion(criterion); /// start the exchange the value of the criterion on the ghost elements this->model.asynchronousSynchronize(_gst_nh_criterion); /// compare to not-ghost neighbors checkNeighbors(_not_ghost); /// finish the exchange this->model.waitEndSynchronize(_gst_nh_criterion); /// compare to ghost neighbors checkNeighbors(_ghost); /// extract the quads with highest criterion in their neighborhood IntegrationPoint quad; quad.ghost_type = _not_ghost; Mesh & mesh = this->model.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost); for (; it != last_type; ++it) { quad.type = *it; Array<bool>::const_scalar_iterator is_highest_it = is_highest(*it, _not_ghost).begin(); Array<bool>::const_scalar_iterator is_highest_end = is_highest(*it, _not_ghost).end(); UInt nb_quadrature_points = this->model.getFEEngine().getNbIntegrationPoints(*it, _not_ghost); UInt q = 0; /// loop over is_highest for the current element type for (; is_highest_it != is_highest_end; ++is_highest_it, ++q) { if (*is_highest_it) { /// gauss point has the highest stress in his neighbourhood quad.element = q / nb_quadrature_points; quad.global_num = q; quad.num_point = q % nb_quadrature_points; max_quads.push_back(quad); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::checkNeighbors(const GhostType & ghost_type2) { AKANTU_DEBUG_IN(); PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); // Compute the weights for (; first_pair != last_pair; ++first_pair) { const IntegrationPoint & lq1 = first_pair->first; const IntegrationPoint & lq2 = first_pair->second; Array<bool> & has_highest_eq_stress_1 = is_highest(lq1.type, lq1.ghost_type); const Array<Real> & criterion_1 = this->criterion(lq1.type, lq1.ghost_type); const Array<Real> & criterion_2 = this->criterion(lq2.type, lq2.ghost_type); if (criterion_1(lq1.global_num) < criterion_2(lq2.global_num)) has_highest_eq_stress_1(lq1.global_num) = false; else if (ghost_type2 != _ghost) { Array<bool> & has_highest_eq_stress_2 = is_highest(lq2.type, lq2.ghost_type); has_highest_eq_stress_2(lq2.global_num) = false; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodMaxCriterion::cleanupExtraGhostElements( const ElementTypeMap<UInt> & nb_ghost_protected) { Mesh & mesh = this->model.getMesh(); /// create remove elements event RemovedElementsEvent remove_elem(mesh); /// create set of ghosts to keep std::set<Element> relevant_ghost_elements; PairList::const_iterator first_pair = pair_list[_ghost].begin(); PairList::const_iterator last_pair = pair_list[_ghost].end(); for (; first_pair != last_pair; ++first_pair) { const IntegrationPoint & q2 = first_pair->second; relevant_ghost_elements.insert(q2); } Array<Element> ghosts_to_erase(0); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); Element element; element.ghost_type = _ghost; auto end = relevant_ghost_elements.end(); for (; it != last_type; ++it) { element.type = *it; UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); UInt nb_ghost_elem_protected = 0; try { nb_ghost_elem_protected = nb_ghost_protected(*it, _ghost); } catch (...) { } if (!remove_elem.getNewNumbering().exists(*it, _ghost)) remove_elem.getNewNumbering().alloc(nb_ghost_elem, 1, *it, _ghost); else remove_elem.getNewNumbering(*it, _ghost).resize(nb_ghost_elem); Array<UInt> & new_numbering = remove_elem.getNewNumbering(*it, _ghost); for (UInt g = 0; g < nb_ghost_elem; ++g) { element.element = g; if (element.element >= nb_ghost_elem_protected && relevant_ghost_elements.find(element) == end) { ghosts_to_erase.push_back(element); new_numbering(element.element) = UInt(-1); } } /// renumber remaining ghosts UInt ng = 0; for (UInt g = 0; g < nb_ghost_elem; ++g) { if (new_numbering(g) != UInt(-1)) { new_numbering(g) = ng; ++ng; } } } mesh.sendEvent(remove_elem); this->onElementsRemoved(ghosts_to_erase, remove_elem.getNewNumbering(), remove_elem); } } // namespace akantu diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh index dbf7f3740..78532e1de 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh @@ -1,280 +1,280 @@ /** * @file non_local_neighborhood_tmpl.hh * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Sep 28 2015 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of class non-local neighborhood * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "non_local_manager.hh" #include "non_local_neighborhood.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class WeightFunction> template <class Func> inline void NonLocalNeighborhood<WeightFunction>::foreach_weight( const GhostType & ghost_type, Func && func) { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward<decltype(func)>(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template <class WeightFunction> template <class Func> inline void NonLocalNeighborhood<WeightFunction>::foreach_weight( const GhostType & ghost_type, Func && func) const { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward<decltype(func)>(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template <class WeightFunction> NonLocalNeighborhood<WeightFunction>::NonLocalNeighborhood( NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : NonLocalNeighborhoodBase(manager.getModel(), quad_coordinates, id, memory_id), non_local_manager(manager) { AKANTU_DEBUG_IN(); this->weight_function = std::make_unique<WeightFunction>(manager); this->registerSubSection(ParserType::_weight_function, "weight_parameter", *weight_function); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class WeightFunction> NonLocalNeighborhood<WeightFunction>::~NonLocalNeighborhood() = default; /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::computeWeights() { AKANTU_DEBUG_IN(); this->weight_function->setRadius(this->neighborhood_radius); Vector<Real> q1_coord(this->spatial_dimension); Vector<Real> q2_coord(this->spatial_dimension); UInt nb_weights_per_pair = 2; /// w1: q1->q2, w2: q2->q1 /// get the elementtypemap for the neighborhood volume for each quadrature /// point ElementTypeMapReal & quadrature_points_volumes = this->non_local_manager.getVolumes(); /// update the internals of the weight function if applicable (not /// all the weight functions have internals and do noting in that /// case) weight_function->updateInternals(); for (auto ghost_type : ghost_types) { /// allocate the array to store the weight, if it doesn't exist already if (!(pair_weight[ghost_type])) { pair_weight[ghost_type] = std::make_unique<Array<Real>>(0, nb_weights_per_pair); } /// resize the array to the correct size pair_weight[ghost_type]->resize(pair_list[ghost_type].size()); /// set entries to zero pair_weight[ghost_type]->clear(); /// loop over all pairs in the current pair list array and their /// corresponding weights auto first_pair = pair_list[ghost_type].begin(); auto last_pair = pair_list[ghost_type].end(); - Array<Real>::vector_iterator weight_it = + auto weight_it = pair_weight[ghost_type]->begin(nb_weights_per_pair); // Compute the weights for (; first_pair != last_pair; ++first_pair, ++weight_it) { Vector<Real> & weight = *weight_it; const IntegrationPoint & q1 = first_pair->first; const IntegrationPoint & q2 = first_pair->second; /// get the coordinates for the given pair of quads - Array<Real>::const_vector_iterator coords_type_1_it = + auto coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(this->spatial_dimension); q1_coord = coords_type_1_it[q1.global_num]; - Array<Real>::const_vector_iterator coords_type_2_it = + auto coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(this->spatial_dimension); q2_coord = coords_type_2_it[q2.global_num]; Array<Real> & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); const Array<Real> & jacobians_2 = this->non_local_manager.getJacobians(q2.type, q2.ghost_type); const Real & q2_wJ = jacobians_2(q2.global_num); /// compute distance between the two quadrature points Real r = q1_coord.distance(q2_coord); /// compute the weight for averaging on q1 based on the distance Real w1 = this->weight_function->operator()(r, q1, q2); weight(0) = q2_wJ * w1; quad_volumes_1(q1.global_num) += weight(0); if (q2.ghost_type != _ghost && q1.global_num != q2.global_num) { const Array<Real> & jacobians_1 = this->non_local_manager.getJacobians(q1.type, q1.ghost_type); Array<Real> & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); /// compute the weight for averaging on q2 const Real & q1_wJ = jacobians_1(q1.global_num); Real w2 = this->weight_function->operator()(r, q2, q1); weight(1) = q1_wJ * w2; quad_volumes_2(q2.global_num) += weight(1); } else weight(1) = 0.; } } /// normalize the weights for (auto ghost_type : ghost_types) { foreach_weight(ghost_type, [&]( const auto & q1, const auto & q2, auto & weight) { auto & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); auto & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); Real q1_volume = quad_volumes_1(q1.global_num); auto ghost_type2 = q2.ghost_type; weight(0) *= 1. / q1_volume; if (ghost_type2 != _ghost) { Real q2_volume = quad_volumes_2(q2.global_num); weight(1) *= 1. / q2_volume; } }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::saveWeights( const std::string & filename) const { std::ofstream pout; std::stringstream sstr; const Communicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { auto ghost_type = (GhostType)gt; AKANTU_DEBUG_ASSERT((pair_weight[ghost_type]), "the weights have not been computed yet"); Array<Real> & weights = *(pair_weight[ghost_type]); - Array<Real>::const_vector_iterator weights_it = weights.begin(2); + auto weights_it = weights.begin(2); for (UInt i = 0; i < weights.size(); ++i, ++weights_it) pout << "w1: " << (*weights_it)(0) << " w2: " << (*weights_it)(1) << std::endl; } } /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::weightedAverageOnNeighbours( const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const { auto it = non_local_variables.find(accumulated.getName()); // do averaging only for variables registered in the neighborhood if (it == non_local_variables.end()) return; foreach_weight( ghost_type2, [ghost_type2, nb_degree_of_freedom, &to_accumulate, &accumulated](const auto & q1, const auto & q2, auto & weight) { const Vector<Real> to_acc_1 = to_accumulate(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; const Vector<Real> to_acc_2 = to_accumulate(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; Vector<Real> acc_1 = accumulated(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; Vector<Real> acc_2 = accumulated(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; acc_1 += weight(0) * to_acc_2; if (ghost_type2 != _ghost) { acc_2 += weight(1) * to_acc_1; } }); } /* -------------------------------------------------------------------------- */ template <class WeightFunction> void NonLocalNeighborhood<WeightFunction>::updateWeights() { // Update the weights for the non local variable averaging if (this->weight_function->getUpdateRate() && (this->non_local_manager.getNbStressCalls() % this->weight_function->getUpdateRate() == 0)) { SynchronizerRegistry::synchronize(_gst_mnl_weight); this->computeWeights(); } } } // namespace akantu #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL__ */ diff --git a/src/model/model.cc b/src/model/model.cc index 7b0e963dd..684e072c8 100644 --- a/src/model/model.cc +++ b/src/model/model.cc @@ -1,370 +1,370 @@ /** * @file model.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Oct 03 2011 * @date last modification: Thu Nov 19 2015 * * @brief implementation of model common parts * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "model.hh" #include "communicator.hh" #include "data_accessor.hh" #include "element_group.hh" #include "element_synchronizer.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Model::Model(Mesh & mesh, const ModelType & type, UInt dim, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), ModelSolver(mesh, type, id, memory_id), mesh(mesh), spatial_dimension(dim == _all_dimensions ? mesh.getSpatialDimension() : dim), is_pbc_slave_node(0, 1, "is_pbc_slave_node"), parser(getStaticParser()) { AKANTU_DEBUG_IN(); this->mesh.registerEventHandler(*this, _ehp_model); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Model::~Model() = default; /* -------------------------------------------------------------------------- */ // void Model::setParser(Parser & parser) { this->parser = &parser; } /* -------------------------------------------------------------------------- */ void Model::initFullImpl(const ModelOptions & options) { AKANTU_DEBUG_IN(); method = options.analysis_method; if (!this->hasDefaultSolver()) { this->initNewSolver(this->method); } initModel(); initFEEngineBoundary(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Model::initNewSolver(const AnalysisMethod & method) { ID solver_name; TimeStepSolverType tss_type; std::tie(solver_name, tss_type) = this->getDefaultSolverID(method); if (not this->hasSolver(solver_name)) { ModelSolverOptions options = this->getDefaultSolverOptions(tss_type); this->getNewSolver(solver_name, tss_type, options.non_linear_solver_type); for (auto && is_type : options.integration_scheme_type) { if (!this->hasIntegrationScheme(solver_name, is_type.first)) { this->setIntegrationScheme(solver_name, is_type.first, is_type.second, options.solution_type[is_type.first]); } } } this->method = method; this->setDefaultSolver(solver_name); } /* -------------------------------------------------------------------------- */ void Model::initPBC() { auto it = pbc_pair.begin(); auto end = pbc_pair.end(); is_pbc_slave_node.resize(mesh.getNbNodes()); #ifndef AKANTU_NDEBUG - Array<Real>::const_vector_iterator coord_it = + auto coord_it = mesh.getNodes().begin(this->spatial_dimension); #endif while (it != end) { UInt i1 = (*it).first; is_pbc_slave_node(i1) = true; #ifndef AKANTU_NDEBUG UInt i2 = (*it).second; UInt slave = mesh.isDistributed() ? mesh.getGlobalNodesIds()(i1) : i1; UInt master = mesh.isDistributed() ? mesh.getGlobalNodesIds()(i2) : i2; AKANTU_DEBUG_INFO("pairing " << slave << " (" << Vector<Real>(coord_it[i1]) << ") with " << master << " (" << Vector<Real>(coord_it[i2]) << ")"); #endif ++it; } } /* -------------------------------------------------------------------------- */ void Model::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_not_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_ghost); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name, const std::string & dumper_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup() { auto bit = mesh.element_group_begin(); auto bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->dump(); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory) { auto bit = mesh.element_group_begin(); auto bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->setDirectory(directory); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setGroupBaseName(const std::string & basename, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setBaseName(basename); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Model::getGroupDumper(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); return group.getDumper(); } /* -------------------------------------------------------------------------- */ // DUMPER stuff /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & field_id, dumper::Field * field, DumperIOHelper & dumper) { #ifdef AKANTU_USE_IOHELPER dumper.registerField(field_id, field); #endif } /* -------------------------------------------------------------------------- */ void Model::addDumpField(const std::string & field_id) { this->addDumpFieldToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVector(const std::string & field_id) { this->addDumpFieldVectorToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensor(const std::string & field_id) { this->addDumpFieldTensorToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseName(const std::string & field_id) { mesh.setBaseName(field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseNameToDumper(const std::string & dumper_name, const std::string & basename) { mesh.setBaseNameToDumper(dumper_name, basename); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, false); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldToDumper(group.getDefaultDumperName(), field_id, group_name, _ek_regular, false); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->removeDumpGroupFieldFromDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.removeDumpFieldFromDumper(dumper_name, field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldVectorToDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { this->addDumpGroupFieldToDumper(dumper_name, field_id, group_name, _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { this->addDumpGroupFieldToDumper(dumper_name, field_id, group_name, this->spatial_dimension, element_kind, padding_flag); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, UInt spatial_dimension, const ElementKind & element_kind, bool padding_flag) { #ifdef AKANTU_USE_IOHELPER dumper::Field * field = nullptr; if (!field) field = this->createNodalFieldReal(field_id, group_name, padding_flag); if (!field) field = this->createNodalFieldUInt(field_id, group_name, padding_flag); if (!field) field = this->createNodalFieldBool(field_id, group_name, padding_flag); if (!field) field = this->createElementalField(field_id, group_name, padding_flag, spatial_dimension, element_kind); if (!field) field = this->mesh.createFieldFromAttachedData<UInt>(field_id, group_name, element_kind); if (!field) field = this->mesh.createFieldFromAttachedData<Real>(field_id, group_name, element_kind); #ifndef AKANTU_NDEBUG if (!field) { AKANTU_DEBUG_WARNING("No field could be found based on name: " << field_id); } #endif if (field) { DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name, group_name); this->addDumpGroupFieldToDumper(field_id, field, dumper); } #endif } /* -------------------------------------------------------------------------- */ void Model::dump() { mesh.dump(); } /* -------------------------------------------------------------------------- */ void Model::setDirectory(const std::string & directory) { mesh.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setDirectoryToDumper(const std::string & dumper_name, const std::string & directory) { mesh.setDirectoryToDumper(dumper_name, directory); } /* -------------------------------------------------------------------------- */ void Model::setTextModeToDumper() { mesh.setTextModeToDumper(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/material_inline_impl.cc b/src/model/solid_mechanics/material_inline_impl.cc index 494cda3d8..303d71707 100644 --- a/src/model/solid_mechanics/material_inline_impl.cc +++ b/src/model/solid_mechanics/material_inline_impl.cc @@ -1,475 +1,475 @@ /** * @file material_inline_impl.cc * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of the inline functions of the class material * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const ElementType & type, UInt element, const GhostType & ghost_type) { Array<UInt> & el_filter = this->element_filter(type, ghost_type); el_filter.push_back(element); return el_filter.size() - 1; } /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const Element & element) { return this->addElement(element.type, element.element, element.ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Material::getTangentStiffnessVoigtSize(UInt dim) const { return (dim * (dim - 1) / 2 + dim); } /* -------------------------------------------------------------------------- */ inline UInt Material::getCauchyStressMatrixSize(UInt dim) const { return (dim * dim); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToF(const Matrix<Real> & grad_u, Matrix<Real> & F) { AKANTU_DEBUG_ASSERT(F.size() >= grad_u.size() && grad_u.size() == dim * dim, "The dimension of the tensor F should be greater or " "equal to the dimension of the tensor grad_u."); F.eye(); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) F(i, j) += grad_u(i, j); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::computeCauchyStressOnQuad(const Matrix<Real> & F, const Matrix<Real> & piola, Matrix<Real> & sigma, const Real & C33) const { Real J = F.det() * sqrt(C33); Matrix<Real> F_S(dim, dim); F_S.mul<false, false>(F, piola); Real constant = J ? 1. / J : 0; sigma.mul<false, true>(F_S, F, constant); } /* -------------------------------------------------------------------------- */ inline void Material::rightCauchy(const Matrix<Real> & F, Matrix<Real> & C) { C.mul<true, false>(F, F); } /* -------------------------------------------------------------------------- */ inline void Material::leftCauchy(const Matrix<Real> & F, Matrix<Real> & B) { B.mul<false, true>(F, F); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) { for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) = 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToGreenStrain(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) { epsilon.mul<true, false>(grad_u, grad_u, .5); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) += 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ inline Real Material::stressToVonMises(const Matrix<Real> & stress) { // compute deviatoric stress UInt dim = stress.cols(); Matrix<Real> deviatoric_stress = Matrix<Real>::eye(dim, -1. * stress.trace() / 3.); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) deviatoric_stress(i, j) += stress(i, j); // return Von Mises stress return std::sqrt(3. * deviatoric_stress.doubleDot(deviatoric_stress) / 2.); } /* ---------------------------------------------------------------------------*/ template <UInt dim> inline void Material::setCauchyStressArray(const Matrix<Real> & S_t, Matrix<Real> & sigma_voight) { AKANTU_DEBUG_IN(); sigma_voight.clear(); // see Finite element formulations for large deformation dynamic analysis, // Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau /* * 1d: [ s11 ]' * 2d: [ s11 s22 s12 ]' * 3d: [ s11 s22 s33 s23 s13 s12 ] */ for (UInt i = 0; i < dim; ++i) // diagonal terms sigma_voight(i, 0) = S_t(i, i); for (UInt i = 1; i < dim; ++i) // term s12 in 2D and terms s23 s13 in 3D sigma_voight(dim + i - 1, 0) = S_t(dim - i - 1, dim - 1); for (UInt i = 2; i < dim; ++i) // term s13 in 3D sigma_voight(dim + i, 0) = S_t(0, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::setCauchyStressMatrix(const Matrix<Real> & S_t, Matrix<Real> & sigma) { AKANTU_DEBUG_IN(); sigma.clear(); /// see Finite ekement formulations for large deformation dynamic analysis, /// Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau for (UInt i = 0; i < dim; ++i) { for (UInt m = 0; m < dim; ++m) { for (UInt n = 0; n < dim; ++n) { sigma(i * dim + m, i * dim + n) = S_t(m, n); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline Element Material::convertToLocalElement(const Element & global_element) const { UInt ge = global_element.element; #ifndef AKANTU_NDEBUG UInt model_mat_index = this->model.getMaterialByElement( global_element.type, global_element.ghost_type)(ge); UInt mat_index = this->model.getMaterialIndex(this->name); AKANTU_DEBUG_ASSERT(model_mat_index == mat_index, "Conversion of a global element in a local element for " "the wrong material " << this->name << std::endl); #endif UInt le = this->model.getMaterialLocalNumbering( global_element.type, global_element.ghost_type)(ge); Element tmp_quad{global_element.type, le, global_element.ghost_type}; return tmp_quad; } /* -------------------------------------------------------------------------- */ inline Element Material::convertToGlobalElement(const Element & local_element) const { UInt le = local_element.element; UInt ge = this->element_filter(local_element.type, local_element.ghost_type)(le); Element tmp_quad{local_element.type, ge, local_element.ghost_type}; return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToLocalPoint(const IntegrationPoint & global_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(global_point.type); Element el = this->convertToLocalElement(static_cast<const Element &>(global_point)); IntegrationPoint tmp_quad(el, global_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToGlobalPoint(const IntegrationPoint & local_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(local_point.type); Element el = this->convertToGlobalElement(static_cast<const Element &>(local_point)); IntegrationPoint tmp_quad(el, local_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline UInt Material::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { return (this->isFiniteDeformation() ? 3 : 1) * spatial_dimension * spatial_dimension * sizeof(Real) * this->getModel().getNbIntegrationPoints(elements); } return 0; } /* -------------------------------------------------------------------------- */ inline void Material::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { packElementDataHelper(piola_kirchhoff_2, buffer, elements); packElementDataHelper(gradu, buffer, elements); } packElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline void Material::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { unpackElementDataHelper(piola_kirchhoff_2, buffer, elements); unpackElementDataHelper(gradu, buffer, elements); } unpackElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline const Parameter & Material::getParam(const ID & param) const { try { return get(param); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::setParam(const ID & param, T value) { try { set<T>(param, value); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } updateInternalParameters(); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::setParamNoUpdate(const ID & param, T value) { try { set<T>(param, value); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::packElementDataHelper( const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id) const { DataAccessor::packElementalDataHelper<T>(data_to_pack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::unpackElementDataHelper( ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id) { DataAccessor::unpackElementalDataHelper<T>(data_to_unpack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template <> inline void Material::registerInternal<Real>(InternalField<Real> & vect) { internal_vectors_real[vect.getID()] = &vect; } template <> inline void Material::registerInternal<UInt>(InternalField<UInt> & vect) { internal_vectors_uint[vect.getID()] = &vect; } template <> inline void Material::registerInternal<bool>(InternalField<bool> & vect) { internal_vectors_bool[vect.getID()] = &vect; } /* -------------------------------------------------------------------------- */ template <> inline void Material::unregisterInternal<Real>(InternalField<Real> & vect) { internal_vectors_real.erase(vect.getID()); } template <> inline void Material::unregisterInternal<UInt>(InternalField<UInt> & vect) { internal_vectors_uint.erase(vect.getID()); } template <> inline void Material::unregisterInternal<bool>(InternalField<bool> & vect) { internal_vectors_bool.erase(vect.getID()); } /* -------------------------------------------------------------------------- */ template <typename T> inline bool Material::isInternal(__attribute__((unused)) const ID & id, __attribute__((unused)) const ElementKind & element_kind) const { AKANTU_TO_IMPLEMENT(); } template <> inline bool Material::isInternal<Real>(const ID & id, const ElementKind & element_kind) const { auto internal_array = internal_vectors_real.find(this->getID() + ":" + id); if (internal_array == internal_vectors_real.end() || internal_array->second->getElementKind() != element_kind) return false; return true; } /* -------------------------------------------------------------------------- */ template <typename T> inline ElementTypeMap<UInt> Material::getInternalDataPerElem(const ID & field_id, const ElementKind & element_kind) const { if (!this->template isInternal<T>(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField<T> & internal_field = this->template getInternal<T>(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); UInt nb_data_per_quad = internal_field.getNbComponent(); ElementTypeMap<UInt> res; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { using type_iterator = typename InternalField<T>::type_iterator; type_iterator tit = internal_field.firstType(*gt); type_iterator tend = internal_field.lastType(*gt); for (; tit != tend; ++tit) { UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(*tit, *gt); res(*tit, *gt) = nb_data_per_quad * nb_quadrature_points; } } return res; } /* -------------------------------------------------------------------------- */ template <typename T> void Material::flattenInternal(const std::string & field_id, ElementTypeMapArray<T> & internal_flat, const GhostType ghost_type, ElementKind element_kind) const { if (!this->template isInternal<T>(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField<T> & internal_field = this->template getInternal<T>(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); const Mesh & mesh = fe_engine.getMesh(); using type_iterator = typename InternalField<T>::filter_type_iterator; type_iterator tit = internal_field.filterFirstType(ghost_type); type_iterator tend = internal_field.filterLastType(ghost_type); for (; tit != tend; ++tit) { ElementType type = *tit; const Array<Real> & src_vect = internal_field(type, ghost_type); const Array<UInt> & filter = internal_field.getFilter(type, ghost_type); // total number of elements in the corresponding mesh UInt nb_element_dst = mesh.getNbElement(type, ghost_type); // number of element in the internal field UInt nb_element_src = filter.size(); // number of quadrature points per elem UInt nb_quad_per_elem = fe_engine.getNbIntegrationPoints(type); // number of data per quadrature point UInt nb_data_per_quad = internal_field.getNbComponent(); if (!internal_flat.exists(type, ghost_type)) { internal_flat.alloc(nb_element_dst * nb_quad_per_elem, nb_data_per_quad, type, ghost_type); } if (nb_element_src == 0) continue; // number of data per element UInt nb_data = nb_quad_per_elem * nb_data_per_quad; Array<Real> & dst_vect = internal_flat(type, ghost_type); dst_vect.resize(nb_element_dst * nb_quad_per_elem); Array<UInt>::const_scalar_iterator it = filter.begin(); Array<UInt>::const_scalar_iterator end = filter.end(); - Array<Real>::const_vector_iterator it_src = + auto it_src = src_vect.begin_reinterpret(nb_data, nb_element_src); - Array<Real>::vector_iterator it_dst = + auto it_dst = dst_vect.begin_reinterpret(nb_data, nb_element_dst); for (; it != end; ++it, ++it_src) { it_dst[*it] = *it_src; } } } } // akantu #endif /* __AKANTU_MATERIAL_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh index 09caa4037..242d2f561 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh @@ -1,818 +1,818 @@ /** * @file material_reinforcement_tmpl.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Thu Feb 1 2018 * * @brief Reinforcement material * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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_voigthelper.hh" #include "material_reinforcement.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> MaterialReinforcement<Mat, dim>::MaterialReinforcement( EmbeddedInterfaceModel & model, const ID & id) : Mat(model, 1, model.getInterfaceMesh(), model.getFEEngine("EmbeddedInterfaceFEEngine"), id), emodel(model), gradu_embedded("gradu_embedded", *this, 1, model.getFEEngine("EmbeddedInterfaceFEEngine"), this->element_filter), directing_cosines("directing_cosines", *this, 1, model.getFEEngine("EmbeddedInterfaceFEEngine"), this->element_filter), pre_stress("pre_stress", *this, 1, model.getFEEngine("EmbeddedInterfaceFEEngine"), this->element_filter), area(1.0), shape_derivatives() { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initialize() { AKANTU_DEBUG_IN(); this->registerParam("area", area, _pat_parsable | _pat_modifiable, "Reinforcement cross-sectional area"); this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable, "Uniform pre-stress"); // this->unregisterInternal(this->stress); // Fool the AvgHomogenizingFunctor // stress.initialize(dim * dim); // Reallocate the element filter this->element_filter.initialize(this->emodel.getInterfaceMesh(), _spatial_dimension = 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> MaterialReinforcement<Mat, dim>::~MaterialReinforcement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initMaterial() { Mat::initMaterial(); gradu_embedded.initialize(dim * dim); pre_stress.initialize(1); /// We initialise the stuff that is not going to change during the simulation this->initFilters(); this->allocBackgroundShapeDerivatives(); this->initBackgroundShapeDerivatives(); this->initDirectingCosines(); } /* -------------------------------------------------------------------------- */ namespace detail { class FilterInitializer : public MeshElementTypeMapArrayInializer { public: FilterInitializer(EmbeddedInterfaceModel & emodel, const GhostType & ghost_type) : MeshElementTypeMapArrayInializer(emodel.getMesh(), 1, emodel.getSpatialDimension(), ghost_type, _ek_regular) {} UInt size(const ElementType & /*bgtype*/) const override { return 0; } }; } /* -------------------------------------------------------------------------- */ /// Initialize the filter for background elements template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initFilters() { for (auto gt : ghost_types) { for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) { std::string shaped_id = "filter"; if (gt == _ghost) shaped_id += ":ghost"; auto & background = background_filter(std::make_unique<ElementTypeMapArray<UInt>>( "bg_" + shaped_id, this->name), type, gt); auto & foreground = foreground_filter( std::make_unique<ElementTypeMapArray<UInt>>(shaped_id, this->name), type, gt); foreground->initialize(detail::FilterInitializer(emodel, gt), 0, true); background->initialize(detail::FilterInitializer(emodel, gt), 0, true); // Computing filters for (auto && bg_type : background->elementTypes(dim, gt)) { filterInterfaceBackgroundElements( (*foreground)(bg_type), (*background)(bg_type), bg_type, type, gt); } } } } /* -------------------------------------------------------------------------- */ /// Construct a filter for a (interface_type, background_type) pair template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::filterInterfaceBackgroundElements( Array<UInt> & foreground, Array<UInt> & background, const ElementType & type, const ElementType & interface_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); foreground.resize(0); background.resize(0); Array<Element> & elements = emodel.getInterfaceAssociatedElements(interface_type, ghost_type); Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); for (auto & elem_id : elem_filter) { Element & elem = elements(elem_id); if (elem.type == type) { background.push_back(elem.element); foreground.push_back(elem_id); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ namespace detail { class BackgroundShapeDInitializer : public ElementTypeMapArrayInializer { public: BackgroundShapeDInitializer(UInt spatial_dimension, FEEngine & engine, const ElementType & foreground_type, ElementTypeMapArray<UInt> & filter, const GhostType & ghost_type) : ElementTypeMapArrayInializer(spatial_dimension, 0, ghost_type, _ek_regular) { auto nb_quad = engine.getNbIntegrationPoints(foreground_type); // Counting how many background elements are affected by elements of // interface_type for (auto type : filter.elementTypes(this->spatial_dimension)) { // Inserting size array_size_per_bg_type(filter(type).size() * nb_quad, type, this->ghost_type); } } auto elementTypes() const -> decltype(auto) { return array_size_per_bg_type.elementTypes(); } UInt size(const ElementType & bgtype) const { return array_size_per_bg_type(bgtype, this->ghost_type); } UInt nbComponent(const ElementType & bgtype) const { return ShapeFunctions::getShapeDerivativesSize(bgtype); } protected: ElementTypeMap<UInt> array_size_per_bg_type; }; } /** * Background shape derivatives need to be stored per background element * types but also per embedded element type, which is why they are stored * in an ElementTypeMap<ElementTypeMapArray<Real> *>. The outer ElementTypeMap * refers to the embedded types, and the inner refers to the background types. */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::allocBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); for (auto gt : ghost_types) { for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) { std::string shaped_id = "embedded_shape_derivatives"; if (gt == _ghost) shaped_id += ":ghost"; auto & shaped_etma = shape_derivatives( std::make_unique<ElementTypeMapArray<Real>>(shaped_id, this->name), type, gt); shaped_etma->initialize( detail::BackgroundShapeDInitializer( emodel.getSpatialDimension(), emodel.getFEEngine("EmbeddedInterfaceFEEngine"), type, *background_filter(type, gt), gt), 0, true); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); for (auto interface_type : this->element_filter.elementTypes(this->spatial_dimension)) { for (auto type : background_filter(interface_type)->elementTypes(dim)) { computeBackgroundShapeDerivatives(interface_type, type, _not_ghost, this->element_filter(interface_type)); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeBackgroundShapeDerivatives( const ElementType & interface_type, const ElementType & bg_type, GhostType ghost_type, const Array<UInt> & filter) { auto & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); auto & engine = emodel.getFEEngine(); auto & interface_mesh = emodel.getInterfaceMesh(); const auto nb_nodes_elem_bg = Mesh::getNbNodesPerElement(bg_type); // const auto nb_strss = VoigtHelper<dim>::size; const auto nb_quads_per_elem = interface_engine.getNbIntegrationPoints(interface_type); Array<Real> quad_pos(0, dim, "interface_quad_pos"); interface_engine.interpolateOnIntegrationPoints(interface_mesh.getNodes(), quad_pos, dim, interface_type, ghost_type, filter); auto & background_shapesd = (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type); auto & background_elements = (*background_filter(interface_type, ghost_type))(bg_type, ghost_type); auto & foreground_elements = (*foreground_filter(interface_type, ghost_type))(bg_type, ghost_type); auto shapesd_begin = background_shapesd.begin(dim, nb_nodes_elem_bg, nb_quads_per_elem); auto quad_begin = quad_pos.begin(dim, nb_quads_per_elem); for (auto && tuple : zip(background_elements, foreground_elements)) { UInt bg = std::get<0>(tuple), fg = std::get<1>(tuple); for (UInt i = 0; i < nb_quads_per_elem; ++i) { Matrix<Real> shapesd = Tensor3<Real>(shapesd_begin[fg])(i); Vector<Real> quads = Matrix<Real>(quad_begin[fg])(i); engine.computeShapeDerivatives(quads, bg, bg_type, shapesd, ghost_type); } } } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::initDirectingCosines() { AKANTU_DEBUG_IN(); Mesh & mesh = emodel.getInterfaceMesh(); Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost); const UInt voigt_size = VoigtHelper<dim>::size; directing_cosines.initialize(voigt_size); for (; type_it != type_end; ++type_it) { computeDirectingCosines(*type_it, _not_ghost); // computeDirectingCosines(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix( GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = emodel.getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); for (; type_it != type_end; ++type_it) { assembleStiffnessMatrix(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleInternalForces( GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = emodel.getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); for (; type_it != type_end; ++type_it) { this->assembleInternalForces(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = emodel.getInterfaceMesh().firstType(); Mesh::type_iterator last_type = emodel.getInterfaceMesh().lastType(); for (; it != last_type; ++it) { computeGradU(*it, ghost_type); this->computeStress(*it, ghost_type); addPrestress(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::addPrestress(const ElementType & type, GhostType ghost_type) { auto & stress = this->stress(type, ghost_type); auto & sigma_p = this->pre_stress(type, ghost_type); for (auto && tuple : zip(stress, sigma_p)) { std::get<0>(tuple) += std::get<1>(tuple); } } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleInternalForces( const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = emodel.getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end; ++type_it) { assembleInternalForcesInterface(type, *type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Computes and assemble the residual. Residual in reinforcement is computed as: * * \f[ * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s} * \f] */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleInternalForcesInterface( const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt voigt_size = VoigtHelper<dim>::size; FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbIntegrationPoints(interface_type, ghost_type); UInt nb_element = elem_filter.size(); UInt back_dof = dim * nodes_per_background_e; Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( background_type, ghost_type); Array<Real> integrant(nb_quadrature_points * nb_element, back_dof, "integrant"); - Array<Real>::vector_iterator integrant_it = integrant.begin(back_dof); - Array<Real>::vector_iterator integrant_end = integrant.end(back_dof); + auto integrant_it = integrant.begin(back_dof); + auto integrant_end = integrant.end(back_dof); Array<Real>::matrix_iterator B_it = shapesd.begin(dim, nodes_per_background_e); - Array<Real>::vector_iterator C_it = + auto C_it = directing_cosines(interface_type, ghost_type).begin(voigt_size); auto sigma_it = this->stress(interface_type, ghost_type).begin(); Matrix<Real> Bvoigt(voigt_size, back_dof); for (; integrant_it != integrant_end; ++integrant_it, ++B_it, ++C_it, ++sigma_it) { VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, nodes_per_background_e); Vector<Real> & C = *C_it; Vector<Real> & BtCt_sigma = *integrant_it; BtCt_sigma.mul<true>(Bvoigt, C); BtCt_sigma *= *sigma_it * area; } Array<Real> residual_interface(nb_element, back_dof, "residual_interface"); interface_engine.integrate(integrant, residual_interface, back_dof, interface_type, ghost_type, elem_filter); integrant.resize(0); Array<UInt> background_filter(nb_element, 1, "background_filter"); auto & filter = getBackgroundFilter(interface_type, background_type, ghost_type); emodel.getDOFManager().assembleElementalArrayLocalArray( residual_interface, emodel.getInternalForce(), background_type, ghost_type, -1., filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeDirectingCosines( const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = emodel.getInterfaceMesh(); const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const UInt steel_dof = dim * nb_nodes_per_element; const UInt voigt_size = VoigtHelper<dim>::size; const UInt nb_quad_points = emodel.getFEEngine("EmbeddedInterfaceFEEngine") .getNbIntegrationPoints(type, ghost_type); Array<Real> node_coordinates(this->element_filter(type, ghost_type).size(), steel_dof); this->emodel.getFEEngine().template extractNodalToElementField<Real>( interface_mesh, interface_mesh.getNodes(), node_coordinates, type, ghost_type, this->element_filter(type, ghost_type)); Array<Real>::matrix_iterator directing_cosines_it = directing_cosines(type, ghost_type).begin(1, voigt_size); Array<Real>::matrix_iterator node_coordinates_it = node_coordinates.begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator node_coordinates_end = node_coordinates.end(dim, nb_nodes_per_element); for (; node_coordinates_it != node_coordinates_end; ++node_coordinates_it) { for (UInt i = 0; i < nb_quad_points; i++, ++directing_cosines_it) { Matrix<Real> & nodes = *node_coordinates_it; Matrix<Real> & cosines = *directing_cosines_it; computeDirectingCosinesOnQuad(nodes, cosines); } } // Mauro: the directing_cosines internal is defined on the quadrature points // of each element AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix( const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = emodel.getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end; ++type_it) { assembleStiffnessMatrixInterface(type, *type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001) * \f[ * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}} * \f] */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrixInterface( const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt voigt_size = VoigtHelper<dim>::size; FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); Array<Real> & grad_u = gradu_embedded(interface_type, ghost_type); UInt nb_element = elem_filter.size(); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbIntegrationPoints(interface_type, ghost_type); UInt back_dof = dim * nodes_per_background_e; UInt integrant_size = back_dof; grad_u.resize(nb_quadrature_points * nb_element); Array<Real> tangent_moduli(nb_element * nb_quadrature_points, 1, "interface_tangent_moduli"); this->computeTangentModuli(interface_type, tangent_moduli, ghost_type); Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( background_type, ghost_type); Array<Real> integrant(nb_element * nb_quadrature_points, integrant_size * integrant_size, "B^t*C^t*D*C*B"); /// Temporary matrices for integrant product Matrix<Real> Bvoigt(voigt_size, back_dof); Matrix<Real> DCB(1, back_dof); Matrix<Real> CtDCB(voigt_size, back_dof); Array<Real>::scalar_iterator D_it = tangent_moduli.begin(); Array<Real>::scalar_iterator D_end = tangent_moduli.end(); Array<Real>::matrix_iterator C_it = directing_cosines(interface_type, ghost_type).begin(1, voigt_size); Array<Real>::matrix_iterator B_it = shapesd.begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator integrant_it = integrant.begin(integrant_size, integrant_size); for (; D_it != D_end; ++D_it, ++C_it, ++B_it, ++integrant_it) { Real & D = *D_it; Matrix<Real> & C = *C_it; Matrix<Real> & B = *B_it; Matrix<Real> & BtCtDCB = *integrant_it; VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt, nodes_per_background_e); DCB.mul<false, false>(C, Bvoigt); DCB *= D * area; CtDCB.mul<true, false>(C, DCB); BtCtDCB.mul<true, false>(Bvoigt, CtDCB); } tangent_moduli.resize(0); Array<Real> K_interface(nb_element, integrant_size * integrant_size, "K_interface"); interface_engine.integrate(integrant, K_interface, integrant_size * integrant_size, interface_type, ghost_type, elem_filter); integrant.resize(0); // Mauro: Here K_interface contains the local stiffness matrices, // directing_cosines contains the information about the orientation // of the reinforcements, any rotation of the local stiffness matrix // can be done here auto & filter = getBackgroundFilter(interface_type, background_type, ghost_type); emodel.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", K_interface, background_type, ghost_type, _symmetric, filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> Real MaterialReinforcement<Mat, dim>::getEnergy(const std::string & id) { AKANTU_DEBUG_IN(); if (id == "potential") { Real epot = 0.; this->computePotentialEnergyByElements(); Mesh::type_iterator it = this->element_filter.firstType( this->spatial_dimension), end = this->element_filter.lastType( this->spatial_dimension); for (; it != end; ++it) { FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); epot += interface_engine.integrate( this->potential_energy(*it, _not_ghost), *it, _not_ghost, this->element_filter(*it, _not_ghost)); epot *= area; } return epot; } AKANTU_DEBUG_OUT(); return 0; } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> void MaterialReinforcement<Mat, dim>::computeGradU( const ElementType & interface_type, GhostType ghost_type) { // Looping over background types for (auto && bg_type : background_filter(interface_type, ghost_type)->elementTypes(dim)) { const UInt nodes_per_background_e = Mesh::getNbNodesPerElement(bg_type); const UInt voigt_size = VoigtHelper<dim>::size; auto & bg_shapesd = (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type); auto & filter = getBackgroundFilter(interface_type, bg_type, ghost_type); Array<Real> disp_per_element(0, dim * nodes_per_background_e, "disp_elem"); FEEngine::extractNodalToElementField( emodel.getMesh(), emodel.getDisplacement(), disp_per_element, bg_type, ghost_type, filter); Matrix<Real> concrete_du(dim, dim); Matrix<Real> epsilon(dim, dim); Vector<Real> evoigt(voigt_size); for (auto && tuple : zip(make_view(disp_per_element, dim, nodes_per_background_e), make_view(bg_shapesd, dim, nodes_per_background_e), this->gradu(interface_type, ghost_type), make_view(this->directing_cosines(interface_type, ghost_type), voigt_size))) { auto & u = std::get<0>(tuple); auto & B = std::get<1>(tuple); auto & du = std::get<2>(tuple); auto & C = std::get<3>(tuple); concrete_du.mul<false, true>(u, B); auto epsilon = 0.5 * (concrete_du + concrete_du.transpose()); strainTensorToVoigtVector(epsilon, evoigt); du = C.dot(evoigt); } } } /* -------------------------------------------------------------------------- */ /** * The structure of the directing cosines matrix is : * \f{eqnarray*}{ * C_{1,\cdot} & = & (l^2, m^2, n^2, mn, ln, lm) \\ * C_{i,j} & = & 0 * \f} * * with : * \f[ * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot * \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s} * \f] */ template <class Mat, UInt dim> inline void MaterialReinforcement<Mat, dim>::computeDirectingCosinesOnQuad( const Matrix<Real> & nodes, Matrix<Real> & cosines) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(nodes.cols() == 2, "Higher order reinforcement elements not implemented"); const Vector<Real> a = nodes(0), b = nodes(1); Vector<Real> delta = b - a; Real sq_length = 0.; for (UInt i = 0; i < dim; i++) { sq_length += delta(i) * delta(i); } if (dim == 2) { cosines(0, 0) = delta(0) * delta(0); // l^2 cosines(0, 1) = delta(1) * delta(1); // m^2 cosines(0, 2) = delta(0) * delta(1); // lm } else if (dim == 3) { cosines(0, 0) = delta(0) * delta(0); // l^2 cosines(0, 1) = delta(1) * delta(1); // m^2 cosines(0, 2) = delta(2) * delta(2); // n^2 cosines(0, 3) = delta(1) * delta(2); // mn cosines(0, 4) = delta(0) * delta(2); // ln cosines(0, 5) = delta(0) * delta(1); // lm } cosines /= sq_length; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> inline void MaterialReinforcement<Mat, dim>::stressTensorToVoigtVector( const Matrix<Real> & tensor, Vector<Real> & vector) { AKANTU_DEBUG_IN(); for (UInt i = 0; i < dim; i++) { vector(i) = tensor(i, i); } if (dim == 2) { vector(2) = tensor(0, 1); } else if (dim == 3) { vector(3) = tensor(1, 2); vector(4) = tensor(0, 2); vector(5) = tensor(0, 1); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Mat, UInt dim> inline void MaterialReinforcement<Mat, dim>::strainTensorToVoigtVector( const Matrix<Real> & tensor, Vector<Real> & vector) { AKANTU_DEBUG_IN(); for (UInt i = 0; i < dim; i++) { vector(i) = tensor(i, i); } if (dim == 2) { vector(2) = 2 * tensor(0, 1); } else if (dim == 3) { vector(3) = 2 * tensor(1, 2); vector(4) = 2 * tensor(0, 2); vector(5) = 2 * tensor(0, 1); } AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc b/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc index 2ae5024da..8f5d0f5b8 100644 --- a/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc +++ b/src/model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc @@ -1,326 +1,326 @@ /** * @file material_standard_linear_solid_deviatoric.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Vladislav Yastrebov <vladislav.yastrebov@epfl.ch> * * @date creation: Wed May 04 2011 * @date last modification: Thu Oct 15 2015 * * @brief Material Visco-elastic * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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_standard_linear_solid_deviatoric.hh" #include "solid_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialStandardLinearSolidDeviatoric<spatial_dimension>:: MaterialStandardLinearSolidDeviatoric(SolidMechanicsModel & model, const ID & id) : MaterialElastic<spatial_dimension>(model, id), stress_dev("stress_dev", *this), history_integral("history_integral", *this), dissipated_energy("dissipated_energy", *this) { AKANTU_DEBUG_IN(); this->registerParam("Eta", eta, Real(1.), _pat_parsable | _pat_modifiable, "Viscosity"); this->registerParam("Ev", Ev, Real(1.), _pat_parsable | _pat_modifiable, "Stiffness of the viscous element"); this->registerParam("Einf", E_inf, Real(1.), _pat_readable, "Stiffness of the elastic element"); UInt stress_size = spatial_dimension * spatial_dimension; this->stress_dev.initialize(stress_size); this->history_integral.initialize(stress_size); this->dissipated_energy.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); updateInternalParameters(); MaterialElastic<spatial_dimension>::initMaterial(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric< spatial_dimension>::updateInternalParameters() { MaterialElastic<spatial_dimension>::updateInternalParameters(); E_inf = this->E - this->Ev; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric<spatial_dimension>::setToSteadyState( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real> & stress_dev_vect = stress_dev(el_type, ghost_type); Array<Real> & history_int_vect = history_integral(el_type, ghost_type); Array<Real>::matrix_iterator stress_d = stress_dev_vect.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator history_int = history_int_vect.begin(spatial_dimension, spatial_dimension); /// Loop on all quadrature points MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> & dev_s = *stress_d; Matrix<Real> & h = *history_int; /// Compute the first invariant of strain Real Theta = grad_u.trace(); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) { dev_s(i, j) = 2 * this->mu * (.5 * (grad_u(i, j) + grad_u(j, i)) - 1. / 3. * Theta * (i == j)); h(i, j) = 0.; } /// Save the deviator of stress ++stress_d; ++history_int; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric<spatial_dimension>::computeStress( ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Real tau = 0.; // if(std::abs(Ev) > std::numeric_limits<Real>::epsilon()) tau = eta / Ev; Array<Real> & stress_dev_vect = stress_dev(el_type, ghost_type); Array<Real> & history_int_vect = history_integral(el_type, ghost_type); Array<Real>::matrix_iterator stress_d = stress_dev_vect.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator history_int = history_int_vect.begin(spatial_dimension, spatial_dimension); Matrix<Real> s(spatial_dimension, spatial_dimension); Real dt = this->model.getTimeStep(); Real exp_dt_tau = exp(-dt / tau); Real exp_dt_tau_2 = exp(-.5 * dt / tau); Matrix<Real> epsilon_d(spatial_dimension, spatial_dimension); Matrix<Real> epsilon_v(spatial_dimension, spatial_dimension); /// Loop on all quadrature points MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> & dev_s = *stress_d; Matrix<Real> & h = *history_int; s.clear(); sigma.clear(); /// Compute the first invariant of strain Real gamma_inf = E_inf / this->E; Real gamma_v = Ev / this->E; this->template gradUToEpsilon<spatial_dimension>(grad_u, epsilon_d); Real Theta = epsilon_d.trace(); epsilon_v.eye(Theta / Real(3.)); epsilon_d -= epsilon_v; Matrix<Real> U_rond_prim(spatial_dimension, spatial_dimension); U_rond_prim.eye(gamma_inf * this->kpa * Theta); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) { s(i, j) = 2 * this->mu * epsilon_d(i, j); h(i, j) = exp_dt_tau * h(i, j) + exp_dt_tau_2 * (s(i, j) - dev_s(i, j)); dev_s(i, j) = s(i, j); sigma(i, j) = U_rond_prim(i, j) + gamma_inf * s(i, j) + gamma_v * h(i, j); } /// Save the deviator of stress ++stress_d; ++history_int; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; this->updateDissipatedEnergy(el_type, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialStandardLinearSolidDeviatoric< spatial_dimension>::updateDissipatedEnergy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); // if(ghost_type == _ghost) return 0.; Real tau = 0.; tau = eta / Ev; Real * dis_energy = dissipated_energy(el_type, ghost_type).storage(); Array<Real> & stress_dev_vect = stress_dev(el_type, ghost_type); Array<Real> & history_int_vect = history_integral(el_type, ghost_type); Array<Real>::matrix_iterator stress_d = stress_dev_vect.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator history_int = history_int_vect.begin(spatial_dimension, spatial_dimension); Matrix<Real> q(spatial_dimension, spatial_dimension); Matrix<Real> q_rate(spatial_dimension, spatial_dimension); Matrix<Real> epsilon_d(spatial_dimension, spatial_dimension); Matrix<Real> epsilon_v(spatial_dimension, spatial_dimension); Real dt = this->model.getTimeStep(); Real gamma_v = Ev / this->E; Real alpha = 1. / (2. * this->mu * gamma_v); /// Loop on all quadrature points MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> & dev_s = *stress_d; Matrix<Real> & h = *history_int; /// Compute the first invariant of strain this->template gradUToEpsilon<spatial_dimension>(grad_u, epsilon_d); Real Theta = epsilon_d.trace(); epsilon_v.eye(Theta / Real(3.)); epsilon_d -= epsilon_v; q.copy(dev_s); q -= h; q *= gamma_v; q_rate.copy(dev_s); q_rate *= gamma_v; q_rate -= q; q_rate /= tau; for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) *dis_energy += (epsilon_d(i, j) - alpha * q(i, j)) * q_rate(i, j) * dt; /// Save the deviator of stress ++stress_d; ++history_int; ++dis_energy; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric< spatial_dimension>::getDissipatedEnergy() const { AKANTU_DEBUG_IN(); Real de = 0.; /// integrate the dissipated energy for each type of elements for (auto & type : this->element_filter.elementTypes(spatial_dimension, _not_ghost)) { de += this->fem.integrate(dissipated_energy(type, _not_ghost), type, _not_ghost, this->element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return de; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric< spatial_dimension>::getDissipatedEnergy(ElementType type, UInt index) const { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = this->fem.getNbIntegrationPoints(type); - Array<Real>::const_vector_iterator it = + auto it = this->dissipated_energy(type, _not_ghost).begin(nb_quadrature_points); UInt gindex = (this->element_filter(type, _not_ghost))(index); AKANTU_DEBUG_OUT(); return this->fem.integrate(it[index], type, gindex); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric<spatial_dimension>::getEnergy( const std::string & type) { if (type == "dissipated") return getDissipatedEnergy(); else if (type == "dissipated_sls_deviatoric") return getDissipatedEnergy(); else return MaterialElastic<spatial_dimension>::getEnergy(type); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> Real MaterialStandardLinearSolidDeviatoric<spatial_dimension>::getEnergy( const std::string & energy_id, ElementType type, UInt index) { if (energy_id == "dissipated") return getDissipatedEnergy(type, index); else if (energy_id == "dissipated_sls_deviatoric") return getDissipatedEnergy(type, index); else return MaterialElastic<spatial_dimension>::getEnergy(energy_id, type, index); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(sls_deviatoric, MaterialStandardLinearSolidDeviatoric); } // namespace akantu diff --git a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc index e8e9108ba..714f57229 100644 --- a/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc +++ b/src/model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc @@ -1,117 +1,117 @@ /** * @file stress_based_weight_function.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Aug 24 2015 * @date last modification: Wed Oct 07 2015 * * @brief implementation of the stres based weight function classes * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 "stress_based_weight_function.hh" namespace akantu { /* -------------------------------------------------------------------------- */ StressBasedWeightFunction::StressBasedWeightFunction(NonLocalManager & manager) : BaseWeightFunction(manager, "stress_based") // stress_diag("stress_diag", material), selected_stress_diag(NULL), // stress_base("stress_base", material), selected_stress_base(NULL), // characteristic_size("lc", material), selected_characteristic_size(NULL) { // this->registerParam("ft", this->ft, 0., _pat_parsable, "Tensile strength"); // stress_diag.initialize(spatial_dimension); // stress_base.initialize(spatial_dimension * spatial_dimension); // characteristic_size.initialize(1); } /* -------------------------------------------------------------------------- */ /// During intialization the characteristic sizes for all quadrature /// points are computed void StressBasedWeightFunction::init() { // const Mesh & mesh = this->material.getModel().getFEEngine().getMesh(); // for (UInt g = _not_ghost; g <= _ghost; ++g) { // GhostType gt = GhostType(g); // Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt); // Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, gt); // for(; it != last_type; ++it) { // UInt nb_quadrature_points = // this->material.getModel().getFEEngine().getNbQuadraturePoints(*it, gt); // const Array<UInt> & element_filter = this->material.getElementFilter(*it, gt); // UInt nb_element = element_filter.size(); // Array<Real> ones(nb_element*nb_quadrature_points, 1, 1.); // Array<Real> & lc = characteristic_size(*it, gt); // this->material.getModel().getFEEngine().integrateOnQuadraturePoints(ones, // lc, // 1, // *it, // gt, // element_filter); // for (UInt q = 0; q < nb_quadrature_points * nb_element; q++) { // lc(q) = pow(lc(q), 1./ Real(spatial_dimension)); // } // } // } } /* -------------------------------------------------------------------------- */ /// computation of principals stresses and principal directions void StressBasedWeightFunction::updatePrincipalStress(__attribute__((unused)) GhostType ghost_type) { // AKANTU_DEBUG_IN(); // const Mesh & mesh = this->material.getModel().getFEEngine().getMesh(); // Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); // Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); // for(; it != last_type; ++it) { // Array<Real>::const_matrix_iterator sigma = // this->material.getStress(*it, ghost_type).begin(spatial_dimension, spatial_dimension); -// Array<Real>::vector_iterator eigenvalues = +// auto eigenvalues = // stress_diag(*it, ghost_type).begin(spatial_dimension); -// Array<Real>::vector_iterator eigenvalues_end = +// auto eigenvalues_end = // stress_diag(*it, ghost_type).end(spatial_dimension); // Array<Real>::matrix_iterator eigenvector = // stress_base(*it, ghost_type).begin(spatial_dimension, spatial_dimension); // #ifndef __trick__ -// Array<Real>::iterator<Real> cl = characteristic_size(*it, ghost_type).begin(); +// auto cl = characteristic_size(*it, ghost_type).begin(); // #endif // UInt q = 0; // for(;eigenvalues != eigenvalues_end; ++sigma, ++eigenvalues, ++eigenvector, ++cl, ++q) { // sigma->eig(*eigenvalues, *eigenvector); // *eigenvalues /= ft; // #ifndef __trick__ // // specify a lower bound for principal stress based on the size of the element // for (UInt i = 0; i < spatial_dimension; ++i) { // (*eigenvalues)(i) = std::max(*cl / this->R, (*eigenvalues)(i)); // } // #endif // } // } // AKANTU_DEBUG_OUT(); } } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index 189e4a50d..e97927adf 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1195 +1,1195 @@ /** * @file solid_mechanics_model.cc * * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Clement Roux <clement.roux@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Jan 19 2016 * * @brief Implementation of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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 "integrator_gauss.hh" #include "shape_lagrange.hh" #include "solid_mechanics_model_tmpl.hh" #include "communicator.hh" #include "element_synchronizer.hh" #include "sparse_matrix.hh" #include "synchronizer_registry.hh" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif #include "material_non_local.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id, const ModelType model_type) : Model(mesh, model_type, dim, id, memory_id), BoundaryCondition<SolidMechanicsModel>(), f_m2a(1.0), displacement(nullptr), previous_displacement(nullptr), displacement_increment(nullptr), mass(nullptr), velocity(nullptr), acceleration(nullptr), external_force(nullptr), internal_force(nullptr), blocked_dofs(nullptr), current_position(nullptr), material_index("material index", id, memory_id), material_local_numbering("material local numbering", id, memory_id), increment_flag(false), are_materials_instantiated(false) { AKANTU_DEBUG_IN(); this->registerFEEngineObject<MyFEEngineType>("SolidMechanicsFEEngine", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); this->mesh.addDumpMesh(mesh, Model::spatial_dimension, _not_ghost, _ek_regular); #endif material_selector = std::make_shared<DefaultMaterialSelector>(material_index), this->initDOFManager(); this->registerDataAccessor(*this); if (this->mesh.isDistributed()) { auto & synchronizer = this->mesh.getElementSynchronizer(); this->registerSynchronizer(synchronizer, _gst_material_id); this->registerSynchronizer(synchronizer, _gst_smm_mass); this->registerSynchronizer(synchronizer, _gst_smm_stress); this->registerSynchronizer(synchronizer, _gst_smm_boundary); this->registerSynchronizer(synchronizer, _gst_for_dump); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); for (auto & internal : this->registered_internals) { delete internal.second; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setTimeStep(Real time_step, const ID & solver_id) { Model::setTimeStep(time_step, solver_id); #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialization */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilities */ void SolidMechanicsModel::initFullImpl(const ModelOptions & options) { material_index.initialize(mesh, _element_kind = _ek_not_defined, _default_value = UInt(-1), _with_nb_element = true); material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined, _with_nb_element = true); Model::initFullImpl(options); // initialize pbc if (this->pbc_pair.size() != 0) this->initPBC(); // initialize the materials if (this->parser.getLastParsedFile() != "") { this->instantiateMaterials(); } this->initMaterials(); this->initBC(*this, *displacement, *displacement_increment, *external_force); } /* -------------------------------------------------------------------------- */ TimeStepSolverType SolidMechanicsModel::getDefaultSolverType() const { return _tsst_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions SolidMechanicsModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_dynamic_lumped: { options.non_linear_solver_type = _nls_lumped; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case _tsst_static: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } case _tsst_dynamic: { if (this->method == _explicit_consistent_mass) { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; } else { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_trapezoidal_rule_2; options.solution_type["displacement"] = IntegrationScheme::_displacement; } break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } /* -------------------------------------------------------------------------- */ std::tuple<ID, TimeStepSolverType> SolidMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_lumped_mass: { return std::make_tuple("explicit_lumped", _tsst_dynamic_lumped); } case _explicit_consistent_mass: { return std::make_tuple("explicit", _tsst_dynamic); } case _static: { return std::make_tuple("static", _tsst_static); } case _implicit_dynamic: { return std::make_tuple("implicit", _tsst_dynamic); } default: return std::make_tuple("unknown", _tsst_not_defined); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType) { auto & dof_manager = this->getDOFManager(); /* ------------------------------------------------------------------------ */ // for alloc type of solvers this->allocNodalField(this->displacement, spatial_dimension, "displacement"); this->allocNodalField(this->previous_displacement, spatial_dimension, "previous_displacement"); this->allocNodalField(this->displacement_increment, spatial_dimension, "displacement_increment"); this->allocNodalField(this->internal_force, spatial_dimension, "internal_force"); this->allocNodalField(this->external_force, spatial_dimension, "external_force"); this->allocNodalField(this->blocked_dofs, spatial_dimension, "blocked_dofs"); this->allocNodalField(this->current_position, spatial_dimension, "current_position"); // initialize the current positions this->current_position->copy(this->mesh.getNodes()); /* ------------------------------------------------------------------------ */ if (!dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); dof_manager.registerDOFsIncrement("displacement", *this->displacement_increment); dof_manager.registerDOFsPrevious("displacement", *this->previous_displacement); } /* ------------------------------------------------------------------------ */ // for dynamic if (time_step_solver_type == _tsst_dynamic || time_step_solver_type == _tsst_dynamic_lumped) { this->allocNodalField(this->velocity, spatial_dimension, "velocity"); this->allocNodalField(this->acceleration, spatial_dimension, "acceleration"); if (!dof_manager.hasDOFsDerivatives("displacement", 1)) { dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity); dof_manager.registerDOFsDerivative("displacement", 2, *this->acceleration); } } } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleResidual() { AKANTU_DEBUG_IN(); /* ------------------------------------------------------------------------ */ // computes the internal forces this->assembleInternalForces(); /* ------------------------------------------------------------------------ */ this->getDOFManager().assembleToResidual("displacement", *this->external_force, 1); this->getDOFManager().assembleToResidual("displacement", *this->internal_force, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MatrixType SolidMechanicsModel::getMatrixType(const ID & matrix_id) { // \TODO check the materials to know what is the correct answer if (matrix_id == "C") return _mt_not_defined; return _symmetric; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } else if (matrix_id == "M") { this->assembleMass(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { this->assembleMassLumped(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::beforeSolveStep() { for (auto & material : materials) material->beforeSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::afterSolveStep() { for (auto & material : materials) material->afterSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::predictor() { ++displacement_release; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::corrector() { ++displacement_release; } /* -------------------------------------------------------------------------- */ /** * This function computes the internal forces as F_{int} = \int_{\Omega} N * \sigma d\Omega@f$ */ void SolidMechanicsModel::assembleInternalForces() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); this->internal_force->clear(); // compute the stresses of local elements AKANTU_DEBUG_INFO("Compute local stresses"); for (auto & material : materials) { material->computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ if (this->non_local_manager) this->non_local_manager->computeAllNonLocalStresses(); // communicate the stresses AKANTU_DEBUG_INFO("Send data for residual assembly"); this->asynchronousSynchronize(_gst_smm_stress); // assemble the forces due to local stresses AKANTU_DEBUG_INFO("Assemble residual for local elements"); for (auto & material : materials) { material->assembleInternalForces(_not_ghost); } // finalize communications AKANTU_DEBUG_INFO("Wait distant stresses"); this->waitEndSynchronize(_gst_smm_stress); // assemble the stresses due to ghost elements AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for (auto & material : materials) { material->assembleInternalForces(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); // Check if materials need to recompute the matrix bool need_to_reassemble = false; for (auto & material : materials) { need_to_reassemble |= material->hasStiffnessMatrixChanged(); } if (need_to_reassemble) { this->getDOFManager().getMatrix("K").clear(); // call compute stiffness matrix on each local elements for (auto & material : materials) { material->assembleStiffnessMatrix(_not_ghost); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { if (this->current_position_release == this->displacement_release) return; this->current_position->copy(this->mesh.getNodes()); auto cpos_it = this->current_position->begin(Model::spatial_dimension); auto cpos_end = this->current_position->end(Model::spatial_dimension); auto disp_it = this->displacement->begin(Model::spatial_dimension); for (; cpos_it != cpos_end; ++cpos_it, ++disp_it) { *cpos_it += *disp_it; } this->current_position_release = this->displacement_release; } /* -------------------------------------------------------------------------- */ const Array<Real> & SolidMechanicsModel::getCurrentPosition() { this->updateCurrentPosition(); return *this->current_position; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateDataForNonLocalCriterion( ElementTypeMapReal & criterion) { const ID field_name = criterion.getName(); for (auto & material : materials) { if (!material->isInternal<Real>(field_name, _ek_regular)) continue; for (auto ghost_type : ghost_types) { material->flattenInternal(field_name, criterion, ghost_type, _ek_regular); } } } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors mesh.getCommunicator().allReduce(min_dt, SynchronizerOperation::_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Real min_dt = std::numeric_limits<Real>::max(); this->updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, _ek_regular)) { elem.type = type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); auto mat_indexes = material_index(type, ghost_type).begin(); auto mat_loc_num = material_local_numbering(type, ghost_type).begin(); Array<Real> X(0, nb_nodes_per_element * Model::spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, type, _not_ghost); auto X_el = X.begin(Model::spatial_dimension, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++X_el, ++mat_indexes, ++mat_loc_num) { elem.element = *mat_loc_num; Real el_h = getFEEngine().getElementInradius(*X_el, type); Real el_c = this->materials[*mat_indexes]->getCelerity(elem); Real el_dt = el_h / el_c; min_dt = std::min(min_dt, el_dt); } } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy() { AKANTU_DEBUG_IN(); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); if (this->getDOFManager().hasLumpedMatrix("M")) { auto m_it = this->mass->begin(Model::spatial_dimension); auto m_end = this->mass->end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (UInt n = 0; m_it != m_end; ++n, ++m_it, ++v_it) { const Vector<Real> & v = *v_it; const Vector<Real> & m = *m_it; Real mv2 = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); // bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node; // && is_not_pbc_slave_node; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (m(i) > std::numeric_limits<Real>::epsilon()) mv2 += v(i) * v(i) * m(i); } } ekin += mv2; } } else if (this->getDOFManager().hasMatrix("M")) { Array<Real> Mv(nb_nodes, Model::spatial_dimension); this->getDOFManager().getMatrix("M").matVecMul(*this->velocity, Mv); auto mv_it = Mv.begin(Model::spatial_dimension); auto mv_end = Mv.end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (; mv_it != mv_end; ++mv_it, ++v_it) { ekin += v_it->dot(*mv_it); } } else { AKANTU_ERROR("No function called to assemble the mass matrix."); } mesh.getCommunicator().allReduce(ekin, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); Array<Real> vel_on_quad(nb_quadrature_points, Model::spatial_dimension); Array<UInt> filter_element(1, 1, index); getFEEngine().interpolateOnIntegrationPoints(*velocity, vel_on_quad, Model::spatial_dimension, type, _not_ghost, filter_element); - Array<Real>::vector_iterator vit = + auto vit = vel_on_quad.begin(Model::spatial_dimension); - Array<Real>::vector_iterator vend = vel_on_quad.end(Model::spatial_dimension); + auto vend = vel_on_quad.end(Model::spatial_dimension); Vector<Real> rho_v2(nb_quadrature_points); Real rho = materials[material_index(type)(index)]->getRho(); for (UInt q = 0; vit != vend; ++vit, ++q) { rho_v2(q) = rho * vit->dot(*vit); } AKANTU_DEBUG_OUT(); return .5 * getFEEngine().integrate(rho_v2, type, index); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); auto ext_force_it = external_force->begin(Model::spatial_dimension); auto int_force_it = internal_force->begin(Model::spatial_dimension); auto boun_it = blocked_dofs->begin(Model::spatial_dimension); decltype(ext_force_it) incr_or_velo_it; if (this->method == _static) { incr_or_velo_it = this->displacement_increment->begin(Model::spatial_dimension); } else { incr_or_velo_it = this->velocity->begin(Model::spatial_dimension); } Real work = 0.; UInt nb_nodes = this->mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n, ++ext_force_it, ++int_force_it, ++boun_it, ++incr_or_velo_it) { const auto & int_force = *int_force_it; const auto & ext_force = *ext_force_it; const auto & boun = *boun_it; const auto & incr_or_velo = *incr_or_velo_it; bool is_local_node = this->mesh.isLocalOrMasterNode(n); // bool is_not_pbc_slave_node = !this->isPBCSlaveNode(n); bool count_node = is_local_node; // && is_not_pbc_slave_node; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (boun(i)) work -= int_force(i) * incr_or_velo(i); else work += ext_force(i) * incr_or_velo(i); } } } mesh.getCommunicator().allReduce(work, SynchronizerOperation::_sum); if (this->method != _static) work *= this->getTimeStep(); AKANTU_DEBUG_OUT(); return work; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(); } else if (energy_id == "external work") { return getExternalWork(); } Real energy = 0.; for (auto & material : materials) energy += material->getEnergy(energy_id); /// reduction sum over all processors mesh.getCommunicator().allReduce(energy, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id, const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(type, index); } UInt mat_index = this->material_index(type, _not_ghost)(index); UInt mat_loc_num = this->material_local_numbering(type, _not_ghost)(index); Real energy = this->materials[mat_index]->getEnergy(energy_id, type, mat_loc_num); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); this->material_index.initialize(mesh, _element_kind = _ek_not_defined, _with_nb_element = true, _default_value = UInt(-1)); this->material_local_numbering.initialize( mesh, _element_kind = _ek_not_defined, _with_nb_element = true, _default_value = UInt(-1)); ElementTypeMapArray<UInt> filter("new_element_filter", this->getID(), this->getMemoryID()); for (auto & elem : element_list) { if (!filter.exists(elem.type, elem.ghost_type)) filter.alloc(0, 1, elem.type, elem.ghost_type); filter(elem.type, elem.ghost_type).push_back(elem.element); } this->assignMaterialToElements(&filter); for (auto & material : materials) material->onElementsAdded(element_list, event); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved( const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) { for (auto & material : materials) { material->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if (displacement) { displacement->resize(nb_nodes, 0.); ++displacement_release; } if (mass) mass->resize(nb_nodes, 0.); if (velocity) velocity->resize(nb_nodes, 0.); if (acceleration) acceleration->resize(nb_nodes, 0.); if (external_force) external_force->resize(nb_nodes, 0.); if (internal_force) internal_force->resize(nb_nodes, 0.); if (blocked_dofs) blocked_dofs->resize(nb_nodes, 0.); if (current_position) current_position->resize(nb_nodes, 0.); if (previous_displacement) previous_displacement->resize(nb_nodes, 0.); if (displacement_increment) displacement_increment->resize(nb_nodes, 0.); for (auto & material : materials) { material->onNodesAdded(nodes_list, event); } need_to_reassemble_lumped_mass = true; need_to_reassemble_mass = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesRemoved(const Array<UInt> & /*element_list*/, const Array<UInt> & new_numbering, const RemovedNodesEvent & /*event*/) { if (displacement) { mesh.removeNodesFromArray(*displacement, new_numbering); ++displacement_release; } if (mass) mesh.removeNodesFromArray(*mass, new_numbering); if (velocity) mesh.removeNodesFromArray(*velocity, new_numbering); if (acceleration) mesh.removeNodesFromArray(*acceleration, new_numbering); if (internal_force) mesh.removeNodesFromArray(*internal_force, new_numbering); if (external_force) mesh.removeNodesFromArray(*external_force, new_numbering); if (blocked_dofs) mesh.removeNodesFromArray(*blocked_dofs, new_numbering); // if (increment_acceleration) // mesh.removeNodesFromArray(*increment_acceleration, new_numbering); if (displacement_increment) mesh.removeNodesFromArray(*displacement_increment, new_numbering); if (previous_displacement) mesh.removeNodesFromArray(*previous_displacement, new_numbering); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << Model::spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); if (velocity) velocity->printself(stream, indent + 2); if (acceleration) acceleration->printself(stream, indent + 2); if (mass) mass->printself(stream, indent + 2); external_force->printself(stream, indent + 2); internal_force->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + material information [" << std::endl; material_index.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + materials [" << std::endl; for (auto & material : materials) { material->printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeNonLocal() { this->non_local_manager->synchronize(*this, _gst_material_id); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type) { for (auto & mat : materials) { MaterialNonLocalInterface * mat_non_local; if ((mat_non_local = dynamic_cast<MaterialNonLocalInterface *>(mat.get())) == nullptr) continue; ElementTypeMapArray<Real> quadrature_points_coordinates( "quadrature_points_coordinates_tmp_nl", this->id, this->memory_id); quadrature_points_coordinates.initialize(this->getFEEngine(), _nb_component = spatial_dimension, _ghost_type = ghost_type); for (auto & type : quadrature_points_coordinates.elementTypes( Model::spatial_dimension, ghost_type)) { this->getFEEngine().computeIntegrationPointsCoordinates( quadrature_points_coordinates(type, ghost_type), type, ghost_type); } mat_non_local->initMaterialNonLocal(); mat_non_local->insertIntegrationPointsInNeighborhoods( ghost_type, quadrature_points_coordinates); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeNonLocalStresses( const GhostType & ghost_type) { for (auto & mat : materials) { if (dynamic_cast<MaterialNonLocalInterface *>(mat.get()) == nullptr) continue; auto & mat_non_local = dynamic_cast<MaterialNonLocalInterface &>(*mat); mat_non_local.computeNonLocalStresses(ghost_type); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & material : materials) { if (material->isInternal<Real>(field_name, kind)) material->flattenInternal(field_name, internal_flat, ghost_type, kind); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateNonLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & mat : materials) { if (dynamic_cast<MaterialNonLocalInterface *>(mat.get()) == nullptr) continue; auto & mat_non_local = dynamic_cast<MaterialNonLocalInterface &>(*mat); mat_non_local.updateNonLocalInternals(internal_flat, field_name, ghost_type, kind); } } /* -------------------------------------------------------------------------- */ FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) { return dynamic_cast<FEEngine &>( getFEEngineClassBoundary<MyFEEngineType>(name)); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::splitElementByMaterial( const Array<Element> & elements, std::vector<Array<Element>> & elements_per_mat) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; const Array<UInt> * mat_indexes = nullptr; const Array<UInt> * mat_loc_num = nullptr; for (const auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; mat_indexes = &(this->material_index(el.type, el.ghost_type)); mat_loc_num = &(this->material_local_numbering(el.type, el.ghost_type)); } Element mat_el = el; mat_el.element = (*mat_loc_num)(el.element); elements_per_mat[(*mat_indexes)(el.element)].push_back(mat_el); } } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModel::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes_per_element = 0; for (const Element & el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch (tag) { case _gst_material_id: { size += elements.size() * sizeof(UInt); break; } case _gst_smm_mass: { size += nb_nodes_per_element * sizeof(Real) * Model::spatial_dimension; // mass vector break; } case _gst_smm_for_gradu: { size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real); // displacement break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * Model::spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } case _gst_for_dump: { // displacement, velocity, acceleration, residual, force size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real) * 5; break; } default: {} } if (tag != _gst_material_id) { splitByMaterial(elements, [&](auto && mat, auto && elements) { size += mat.getNbData(elements, tag); }); } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); switch (tag) { case _gst_material_id: { this->packElementalDataHelper(material_index, buffer, elements, false, getFEEngine()); break; } case _gst_smm_mass: { packNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { packNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_for_dump: { packNodalDataHelper(*displacement, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*acceleration, buffer, elements, mesh); packNodalDataHelper(*internal_force, buffer, elements, mesh); packNodalDataHelper(*external_force, buffer, elements, mesh); break; } case _gst_smm_boundary: { packNodalDataHelper(*external_force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.packData(buffer, elements, tag); }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); switch (tag) { case _gst_material_id: { for (auto && element : elements) { UInt recv_mat_index; buffer >> recv_mat_index; UInt & mat_index = material_index(element); if (mat_index != UInt(-1)) continue; // add ghosts element to the correct material mat_index = recv_mat_index; UInt index = materials[mat_index]->addElement(element); material_local_numbering(element) = index; } break; } case _gst_smm_mass: { unpackNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_for_dump: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*acceleration, buffer, elements, mesh); unpackNodalDataHelper(*internal_force, buffer, elements, mesh); unpackNodalDataHelper(*external_force, buffer, elements, mesh); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*external_force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.unpackData(buffer, elements, tag); }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModel::getNbData(const Array<UInt> & dofs, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch (tag) { case _gst_smm_uv: { size += sizeof(Real) * Model::spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * Model::spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * Model::spatial_dimension; break; } case _gst_for_dump: { size += sizeof(Real) * Model::spatial_dimension * 5; break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size * dofs.size(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); switch (tag) { case _gst_smm_uv: { packDOFDataHelper(*displacement, buffer, dofs); packDOFDataHelper(*velocity, buffer, dofs); break; } case _gst_smm_res: { packDOFDataHelper(*internal_force, buffer, dofs); break; } case _gst_smm_mass: { packDOFDataHelper(*mass, buffer, dofs); break; } case _gst_for_dump: { packDOFDataHelper(*displacement, buffer, dofs); packDOFDataHelper(*velocity, buffer, dofs); packDOFDataHelper(*acceleration, buffer, dofs); packDOFDataHelper(*internal_force, buffer, dofs); packDOFDataHelper(*external_force, buffer, dofs); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); switch (tag) { case _gst_smm_uv: { unpackDOFDataHelper(*displacement, buffer, dofs); unpackDOFDataHelper(*velocity, buffer, dofs); break; } case _gst_smm_res: { unpackDOFDataHelper(*internal_force, buffer, dofs); break; } case _gst_smm_mass: { unpackDOFDataHelper(*mass, buffer, dofs); break; } case _gst_for_dump: { unpackDOFDataHelper(*displacement, buffer, dofs); unpackDOFDataHelper(*velocity, buffer, dofs); unpackDOFDataHelper(*acceleration, buffer, dofs); unpackDOFDataHelper(*internal_force, buffer, dofs); unpackDOFDataHelper(*external_force, buffer, dofs); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc index 3a3ff1816..acf03716c 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/fragment_manager.cc @@ -1,615 +1,615 @@ /** * @file fragment_manager.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Thu Jan 23 2014 * @date last modification: Mon Dec 14 2015 * * @brief Group manager to handle fragments * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fragment_manager.hh" #include "aka_iterators.hh" #include "material_cohesive.hh" #include "mesh_iterators.hh" #include "solid_mechanics_model_cohesive.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <functional> #include <numeric> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ FragmentManager::FragmentManager(SolidMechanicsModelCohesive & model, bool dump_data, const ID & id, const MemoryID & memory_id) : GroupManager(model.getMesh(), id, memory_id), model(model), mass_center(0, model.getSpatialDimension(), "mass_center"), mass(0, model.getSpatialDimension(), "mass"), velocity(0, model.getSpatialDimension(), "velocity"), inertia_moments(0, model.getSpatialDimension(), "inertia_moments"), principal_directions( 0, model.getSpatialDimension() * model.getSpatialDimension(), "principal_directions"), quad_coordinates("quad_coordinates", id), mass_density("mass_density", id), nb_elements_per_fragment(0, 1, "nb_elements_per_fragment"), dump_data(dump_data) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); /// compute quadrature points' coordinates quad_coordinates.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost); // mesh.initElementTypeMapArray(quad_coordinates, spatial_dimension, // spatial_dimension, _not_ghost); model.getFEEngine().interpolateOnIntegrationPoints(model.getMesh().getNodes(), quad_coordinates); /// store mass density per quadrature point mass_density.initialize(mesh, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost); // mesh.initElementTypeMapArray(mass_density, 1, spatial_dimension, // _not_ghost); storeMassDensityPerIntegrationPoint(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ class CohesiveElementFilter : public GroupManager::ClusteringFilter { public: CohesiveElementFilter(const SolidMechanicsModelCohesive & model, const Real max_damage = 1.) : model(model), is_unbroken(max_damage) {} bool operator()(const Element & el) const override { if (Mesh::getKind(el.type) == _ek_regular) return true; const Array<UInt> & mat_indexes = model.getMaterialByElement(el.type, el.ghost_type); const Array<UInt> & mat_loc_num = model.getMaterialLocalNumbering(el.type, el.ghost_type); const auto & mat = static_cast<const MaterialCohesive &>( model.getMaterial(mat_indexes(el.element))); UInt el_index = mat_loc_num(el.element); UInt nb_quad_per_element = model.getFEEngine("CohesiveFEEngine") .getNbIntegrationPoints(el.type, el.ghost_type); const Array<Real> & damage_array = mat.getDamage(el.type, el.ghost_type); AKANTU_DEBUG_ASSERT(nb_quad_per_element * el_index < damage_array.size(), "This quadrature point is out of range"); const Real * element_damage = damage_array.storage() + nb_quad_per_element * el_index; UInt unbroken_quads = std::count_if( element_damage, element_damage + nb_quad_per_element, is_unbroken); if (unbroken_quads > 0) return true; return false; } private: struct IsUnbrokenFunctor { IsUnbrokenFunctor(const Real & max_damage) : max_damage(max_damage) {} bool operator()(const Real & x) { return x < max_damage; } const Real max_damage; }; const SolidMechanicsModelCohesive & model; const IsUnbrokenFunctor is_unbroken; }; /* -------------------------------------------------------------------------- */ void FragmentManager::buildFragments(Real damage_limit) { AKANTU_DEBUG_IN(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) ElementSynchronizer * cohesive_synchronizer = const_cast<ElementSynchronizer *>(model.getCohesiveSynchronizer()); if (cohesive_synchronizer) { cohesive_synchronizer->computeBufferSize(model, _gst_smmc_damage); cohesive_synchronizer->asynchronousSynchronize(model, _gst_smmc_damage); cohesive_synchronizer->waitEndSynchronize(model, _gst_smmc_damage); } #endif auto & mesh_facets = const_cast<Mesh &>(mesh.getMeshFacets()); UInt spatial_dimension = model.getSpatialDimension(); std::string fragment_prefix("fragment"); /// generate fragments global_nb_fragment = createClusters(spatial_dimension, mesh_facets, fragment_prefix, CohesiveElementFilter(model, damage_limit)); nb_fragment = getNbElementGroups(spatial_dimension); fragment_index.resize(nb_fragment); UInt * fragment_index_it = fragment_index.storage(); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { /// get fragment index std::string fragment_index_string = it->first.substr(fragment_prefix.size() + 1); std::stringstream sstr(fragment_index_string.c_str()); sstr >> *fragment_index_it; AKANTU_DEBUG_ASSERT(!sstr.fail(), "fragment_index is not an integer"); } /// compute fragments' mass computeMass(); if (dump_data) { createDumpDataArray(fragment_index, "fragments", true); createDumpDataArray(mass, "fragments mass"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeMass() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); /// create a unit field per quadrature point, since to compute mass /// it's neccessary to integrate only density ElementTypeMapArray<Real> unit_field("unit_field", id); unit_field.initialize(model.getFEEngine(), _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost, _default_value = 1.); // mesh.initElementTypeMapArray(unit_field, spatial_dimension, // spatial_dimension, // _not_ghost); // ElementTypeMapArray<Real>::type_iterator it = // unit_field.firstType(spatial_dimension, _not_ghost, _ek_regular); // ElementTypeMapArray<Real>::type_iterator end = // unit_field.lastType(spatial_dimension, _not_ghost, _ek_regular); // for (; it != end; ++it) { // ElementType type = *it; // Array<Real> & field_array = unit_field(type); // UInt nb_element = mesh.getNbElement(type); // UInt nb_quad_per_element = // model.getFEEngine().getNbIntegrationPoints(type); // field_array.resize(nb_element * nb_quad_per_element); // field_array.set(1.); // } integrateFieldOnFragments(unit_field, mass); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeCenterOfMass() { AKANTU_DEBUG_IN(); /// integrate position multiplied by density integrateFieldOnFragments(quad_coordinates, mass_center); /// divide it by the fragments' mass Real * mass_storage = mass.storage(); Real * mass_center_storage = mass_center.storage(); UInt total_components = mass_center.size() * mass_center.getNbComponent(); for (UInt i = 0; i < total_components; ++i) mass_center_storage[i] /= mass_storage[i]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeVelocity() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); /// compute velocity per quadrature point ElementTypeMapArray<Real> velocity_field("velocity_field", id); velocity_field.initialize( model.getFEEngine(), _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost); // mesh.initElementTypeMapArray(velocity_field, spatial_dimension, // spatial_dimension, _not_ghost); model.getFEEngine().interpolateOnIntegrationPoints(model.getVelocity(), velocity_field); /// integrate on fragments integrateFieldOnFragments(velocity_field, velocity); /// divide it by the fragments' mass Real * mass_storage = mass.storage(); Real * velocity_storage = velocity.storage(); UInt total_components = velocity.size() * velocity.getNbComponent(); for (UInt i = 0; i < total_components; ++i) velocity_storage[i] /= mass_storage[i]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Given the distance @f$ \mathbf{r} @f$ between a quadrature point * and its center of mass, the moment of inertia is computed as \f[ * I_\mathrm{CM} = \mathrm{tr}(\mathbf{r}\mathbf{r}^\mathrm{T}) * \mathbf{I} - \mathbf{r}\mathbf{r}^\mathrm{T} \f] for more * information check Wikipedia * (http://en.wikipedia.org/wiki/Moment_of_inertia#Identities_for_a_skew-symmetric_matrix) * */ void FragmentManager::computeInertiaMoments() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); computeCenterOfMass(); /// compute local coordinates products with respect to the center of match ElementTypeMapArray<Real> moments_coords("moments_coords", id); moments_coords.initialize(model.getFEEngine(), _nb_component = spatial_dimension * spatial_dimension, _spatial_dimension = spatial_dimension, _ghost_type = _not_ghost, _default_value = 1.); // mesh.initElementTypeMapArray(moments_coords, // spatial_dimension * spatial_dimension, // spatial_dimension, _not_ghost); // /// resize the by element type // ElementTypeMapArray<Real>::type_iterator it = // moments_coords.firstType(spatial_dimension, _not_ghost, _ek_regular); // ElementTypeMapArray<Real>::type_iterator end = // moments_coords.lastType(spatial_dimension, _not_ghost, _ek_regular); // for (; it != end; ++it) { // ElementType type = *it; // Array<Real> & field_array = moments_coords(type); // UInt nb_element = mesh.getNbElement(type); // UInt nb_quad_per_element = // model.getFEEngine().getNbIntegrationPoints(type); // field_array.resize(nb_element * nb_quad_per_element); // } /// compute coordinates - Array<Real>::const_vector_iterator mass_center_it = + auto mass_center_it = mass_center.begin(spatial_dimension); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++mass_center_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); /// loop over elements of the fragment for (auto type : el_list.elementTypes(spatial_dimension, _not_ghost, _ek_regular)) { UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); Array<Real> & moments_coords_array = moments_coords(type); const Array<Real> & quad_coordinates_array = quad_coordinates(type); const Array<UInt> & el_list_array = el_list(type); Array<Real>::matrix_iterator moments_begin = moments_coords_array.begin(spatial_dimension, spatial_dimension); - Array<Real>::const_vector_iterator quad_coordinates_begin = + auto quad_coordinates_begin = quad_coordinates_array.begin(spatial_dimension); Vector<Real> relative_coords(spatial_dimension); for (UInt el = 0; el < el_list_array.size(); ++el) { UInt global_el = el_list_array(el); /// loop over quadrature points for (UInt q = 0; q < nb_quad_per_element; ++q) { UInt global_q = global_el * nb_quad_per_element + q; Matrix<Real> moments_matrix = moments_begin[global_q]; const Vector<Real> & quad_coord_vector = quad_coordinates_begin[global_q]; /// to understand this read the documentation written just /// before this function relative_coords = quad_coord_vector; relative_coords -= *mass_center_it; moments_matrix.outerProduct(relative_coords, relative_coords); Real trace = moments_matrix.trace(); moments_matrix *= -1.; moments_matrix += Matrix<Real>::eye(spatial_dimension, trace); } } } } /// integrate moments Array<Real> integrated_moments(global_nb_fragment, spatial_dimension * spatial_dimension); integrateFieldOnFragments(moments_coords, integrated_moments); /// compute and store principal moments inertia_moments.resize(global_nb_fragment); principal_directions.resize(global_nb_fragment); Array<Real>::matrix_iterator integrated_moments_it = integrated_moments.begin(spatial_dimension, spatial_dimension); - Array<Real>::vector_iterator inertia_moments_it = + auto inertia_moments_it = inertia_moments.begin(spatial_dimension); Array<Real>::matrix_iterator principal_directions_it = principal_directions.begin(spatial_dimension, spatial_dimension); for (UInt frag = 0; frag < global_nb_fragment; ++frag, ++integrated_moments_it, ++inertia_moments_it, ++principal_directions_it) { integrated_moments_it->eig(*inertia_moments_it, *principal_directions_it); } if (dump_data) createDumpDataArray(inertia_moments, "moments of inertia"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeAllData() { AKANTU_DEBUG_IN(); buildFragments(); computeVelocity(); computeInertiaMoments(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::storeMassDensityPerIntegrationPoint() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator end = mesh.lastType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; Array<Real> & mass_density_array = mass_density(type); UInt nb_element = mesh.getNbElement(type); UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); mass_density_array.resize(nb_element * nb_quad_per_element); const Array<UInt> & mat_indexes = model.getMaterialByElement(type); Real * mass_density_it = mass_density_array.storage(); /// store mass_density for each element and quadrature point for (UInt el = 0; el < nb_element; ++el) { Material & mat = model.getMaterial(mat_indexes(el)); for (UInt q = 0; q < nb_quad_per_element; ++q, ++mass_density_it) *mass_density_it = mat.getRho(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::integrateFieldOnFragments( ElementTypeMapArray<Real> & field, Array<Real> & output) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); UInt nb_component = output.getNbComponent(); /// integration part output.resize(global_nb_fragment); output.clear(); UInt * fragment_index_it = fragment_index.storage(); - Array<Real>::vector_iterator output_begin = output.begin(nb_component); + auto output_begin = output.begin(nb_component); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); /// loop over elements of the fragment for (auto type : el_list.elementTypes(spatial_dimension, _not_ghost, _ek_regular)) { UInt nb_quad_per_element = model.getFEEngine().getNbIntegrationPoints(type); const Array<Real> & density_array = mass_density(type); Array<Real> & field_array = field(type); const Array<UInt> & elements = el_list(type); UInt nb_element = elements.size(); /// generate array to be integrated by filtering fragment's elements Array<Real> integration_array(elements.size() * nb_quad_per_element, nb_component); Array<Real>::matrix_iterator int_array_it = integration_array.begin_reinterpret(nb_quad_per_element, nb_component, nb_element); Array<Real>::matrix_iterator int_array_end = integration_array.end_reinterpret(nb_quad_per_element, nb_component, nb_element); Array<Real>::matrix_iterator field_array_begin = field_array.begin_reinterpret(nb_quad_per_element, nb_component, field_array.size() / nb_quad_per_element); - Array<Real>::const_vector_iterator density_array_begin = + auto density_array_begin = density_array.begin_reinterpret(nb_quad_per_element, density_array.size() / nb_quad_per_element); for (UInt el = 0; int_array_it != int_array_end; ++int_array_it, ++el) { UInt global_el = elements(el); *int_array_it = field_array_begin[global_el]; /// multiply field by density const Vector<Real> & density_vector = density_array_begin[global_el]; for (UInt i = 0; i < nb_quad_per_element; ++i) { for (UInt j = 0; j < nb_component; ++j) { (*int_array_it)(i, j) *= density_vector(i); } } } /// integrate the field over the fragment Array<Real> integrated_array(elements.size(), nb_component); model.getFEEngine().integrate(integration_array, integrated_array, nb_component, type, _not_ghost, elements); /// sum over all elements and store the result Vector<Real> output_tmp(output_begin[*fragment_index_it]); output_tmp += std::accumulate(integrated_array.begin(nb_component), integrated_array.end(nb_component), Vector<Real>(nb_component)); } } /// sum output over all processors const Communicator & comm = mesh.getCommunicator(); comm.allReduce(output, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeNbElementsPerFragment() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); nb_elements_per_fragment.resize(global_nb_fragment); nb_elements_per_fragment.clear(); UInt * fragment_index_it = fragment_index.storage(); /// loop over fragments for (const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); /// loop over elements of the fragment for (auto type : el_list.elementTypes(spatial_dimension, _not_ghost, _ek_regular)) { UInt nb_element = el_list(type).size(); nb_elements_per_fragment(*fragment_index_it) += nb_element; } } /// sum values over all processors const auto & comm = mesh.getCommunicator(); comm.allReduce(nb_elements_per_fragment, SynchronizerOperation::_sum); if (dump_data) createDumpDataArray(nb_elements_per_fragment, "elements per fragment"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void FragmentManager::createDumpDataArray(Array<T> & data, std::string name, bool fragment_index_output) { AKANTU_DEBUG_IN(); if (data.size() == 0) return; auto & mesh_not_const = const_cast<Mesh &>(mesh); auto && spatial_dimension = mesh.getSpatialDimension(); auto && nb_component = data.getNbComponent(); auto && data_begin = data.begin(nb_component); auto fragment_index_it = fragment_index.begin(); /// loop over fragments for (const auto & fragment : ElementGroupsIterable(*this)) { const auto & fragment_idx = *fragment_index_it; /// loop over cluster types for (auto & type : fragment.elementTypes(spatial_dimension)) { /// init mesh data auto & mesh_data = mesh_not_const.getDataPointer<T>( name, type, _not_ghost, nb_component); auto mesh_data_begin = mesh_data.begin(nb_component); /// fill mesh data for (const auto & elem : fragment.getElements(type)) { Vector<T> md_tmp = mesh_data_begin[elem]; if (fragment_index_output) { md_tmp(0) = fragment_idx; } else { md_tmp = data_begin[fragment_idx]; } } } } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc index 5e3d137d6..1c936b9c7 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_bilinear.cc @@ -1,219 +1,219 @@ /** * @file material_cohesive_bilinear.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Feb 22 2012 * @date last modification: Thu Oct 15 2015 * * @brief Bilinear cohesive constitutive law * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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_cohesive_bilinear.hh" //#include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveBilinear<spatial_dimension>::MaterialCohesiveBilinear( SolidMechanicsModel & model, const ID & id) : MaterialCohesiveLinear<spatial_dimension>(model, id) { AKANTU_DEBUG_IN(); this->registerParam("delta_0", delta_0, Real(0.), _pat_parsable | _pat_readable, "Elastic limit displacement"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); this->sigma_c_eff.setRandomDistribution(this->sigma_c.getRandomParameter()); MaterialCohesiveLinear<spatial_dimension>::initMaterial(); this->delta_max.setDefaultValue(delta_0); this->insertion_stress.setDefaultValue(0); this->delta_max.reset(); this->insertion_stress.reset(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::onElementsAdded( const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); MaterialCohesiveLinear<spatial_dimension>::onElementsAdded(element_list, event); bool scale_traction = false; // don't scale sigma_c if volume_s hasn't been specified by the user if (!Math::are_float_equal(this->volume_s, 0.)) scale_traction = true; Array<Element>::const_scalar_iterator el_it = element_list.begin(); Array<Element>::const_scalar_iterator el_end = element_list.end(); for (; el_it != el_end; ++el_it) { // filter not ghost cohesive elements if (el_it->ghost_type != _not_ghost || Mesh::getKind(el_it->type) != _ek_cohesive) continue; UInt index = el_it->element; ElementType type = el_it->type; UInt nb_element = this->model->getMesh().getNbElement(type); UInt nb_quad_per_element = this->fem_cohesive.getNbIntegrationPoints(type); - Array<Real>::vector_iterator sigma_c_begin = + auto sigma_c_begin = this->sigma_c_eff(type).begin_reinterpret(nb_quad_per_element, nb_element); Vector<Real> sigma_c_vec = sigma_c_begin[index]; - Array<Real>::vector_iterator delta_c_begin = + auto delta_c_begin = this->delta_c_eff(type).begin_reinterpret(nb_quad_per_element, nb_element); Vector<Real> delta_c_vec = delta_c_begin[index]; if (scale_traction) scaleTraction(*el_it, sigma_c_vec); /** * Recompute sigma_c as * @f$ {\sigma_c}_\textup{new} = * \frac{{\sigma_c}_\textup{old} \delta_c} {\delta_c - \delta_0} @f$ */ for (UInt q = 0; q < nb_quad_per_element; ++q) { delta_c_vec(q) = 2 * this->G_c / sigma_c_vec(q); if (delta_c_vec(q) - delta_0 < Math::getTolerance()) AKANTU_ERROR("delta_0 = " << delta_0 << " must be lower than delta_c = " << delta_c_vec(q) << ", modify your material file"); sigma_c_vec(q) *= delta_c_vec(q) / (delta_c_vec(q) - delta_0); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::scaleTraction( const Element & el, Vector<Real> & sigma_c_vec) { AKANTU_DEBUG_IN(); Real base_sigma_c = this->sigma_c_eff; const Mesh & mesh_facets = this->model->getMeshFacets(); const FEEngine & fe_engine = this->model->getFEEngine(); auto coh_element_to_facet_begin = mesh_facets.getSubelementToElement(el.type).begin(2); const Vector<Element> & coh_element_to_facet = coh_element_to_facet_begin[el.element]; // compute bounding volume Real volume = 0; // loop over facets for (UInt f = 0; f < 2; ++f) { const Element & facet = coh_element_to_facet(f); const Array<std::vector<Element>> & facet_to_element = mesh_facets.getElementToSubelement(facet.type, facet.ghost_type); const std::vector<Element> & element_list = facet_to_element(facet.element); auto elem = element_list.begin(); auto elem_end = element_list.end(); // loop over elements connected to each facet for (; elem != elem_end; ++elem) { // skip cohesive elements and dummy elements if (*elem == ElementNull || Mesh::getKind(elem->type) == _ek_cohesive) continue; // unit vector for integration in order to obtain the volume UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(elem->type); Vector<Real> unit_vector(nb_quadrature_points, 1); volume += fe_engine.integrate(unit_vector, elem->type, elem->element, elem->ghost_type); } } // scale sigma_c sigma_c_vec -= base_sigma_c; sigma_c_vec *= std::pow(this->volume_s / volume, 1. / this->m_s); sigma_c_vec += base_sigma_c; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveBilinear<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialCohesiveLinear<spatial_dimension>::computeTraction(normal, el_type, ghost_type); // adjust damage Array<Real>::scalar_iterator delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_max_it = this->delta_max(el_type, ghost_type).begin(); Array<Real>::scalar_iterator damage_it = this->damage(el_type, ghost_type).begin(); Array<Real>::scalar_iterator damage_end = this->damage(el_type, ghost_type).end(); for (; damage_it != damage_end; ++damage_it, ++delta_max_it, ++delta_c_it) { *damage_it = std::max((*delta_max_it - delta_0) / (*delta_c_it - delta_0), Real(0.)); *damage_it = std::min(*damage_it, Real(1.)); } } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_bilinear, MaterialCohesiveBilinear); } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc index ff2e48708..010024676 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_exponential.cc @@ -1,358 +1,358 @@ /** * @file material_cohesive_exponential.cc * * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Mon Jul 09 2012 * @date last modification: Tue Aug 04 2015 * * @brief Exponential irreversible cohesive law of mixed mode loading * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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_cohesive_exponential.hh" #include "dof_synchronizer.hh" #include "solid_mechanics_model.hh" #include "sparse_matrix.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveExponential<spatial_dimension>::MaterialCohesiveExponential( SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model, id) { AKANTU_DEBUG_IN(); this->registerParam("beta", beta, Real(0.), _pat_parsable, "Beta parameter"); this->registerParam("exponential_penalty", exp_penalty, true, _pat_parsable, "Is contact penalty following the exponential law?"); this->registerParam( "contact_tangent", contact_tangent, Real(1.0), _pat_parsable, "Ratio of contact tangent over the initial exponential tangent"); // this->initInternalArray(delta_max, 1, _ek_cohesive); use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); if ((exp_penalty) && (contact_tangent != 1)) { contact_tangent = 1; AKANTU_DEBUG_WARNING("The parsed paramter <contact_tangent> is forced to " "1.0 when the contact penalty follows the exponential " "law"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators - Array<Real>::vector_iterator traction_it = + auto traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator opening_it = + auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::const_vector_iterator normal_it = + auto normal_it = normal.begin(spatial_dimension); - Array<Real>::vector_iterator traction_end = + auto traction_end = tractions(el_type, ghost_type).end(spatial_dimension); - Array<Real>::iterator<Real> delta_max_it = + auto delta_max_it = delta_max(el_type, ghost_type).begin(); - Array<Real>::iterator<Real> delta_max_prev_it = + auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); /// compute scalars Real beta2 = beta * beta; /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++delta_max_it, ++delta_max_prev_it) { /// compute normal and tangential opening vectors Real normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening(spatial_dimension); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; Vector<Real> tangential_opening(spatial_dimension); tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \beta^2 \Delta_t^2 + \Delta_n^2 } @f$ */ Real delta = tangential_opening_norm; delta *= delta * beta2; delta += normal_opening_norm * normal_opening_norm; delta = sqrt(delta); if ((normal_opening_norm < 0) && (std::abs(normal_opening_norm) > Math::getTolerance())) { Vector<Real> op_n(*normal_it); op_n *= normal_opening_norm; Vector<Real> delta_s(*opening_it); delta_s -= op_n; delta = tangential_opening_norm * beta; computeCoupledTraction(*traction_it, *normal_it, delta, delta_s, *delta_max_it, *delta_max_prev_it); computeCompressiveTraction(*traction_it, *normal_it, normal_opening_norm, *opening_it); } else computeCoupledTraction(*traction_it, *normal_it, delta, *opening_it, *delta_max_it, *delta_max_prev_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCoupledTraction( Vector<Real> & tract, const Vector<Real> & normal, Real delta, const Vector<Real> & opening, Real & delta_max_new, Real delta_max) { AKANTU_DEBUG_IN(); /// full damage case if (std::abs(delta) < Math::getTolerance()) { /// set traction to zero tract.clear(); } else { /// element not fully damaged /** * Compute traction loading @f$ \mathbf{T} = * e \sigma_c \frac{\delta}{\delta_c} e^{-\delta/ \delta_c}@f$ */ /** * Compute traction unloading @f$ \mathbf{T} = * \frac{t_{max}}{\delta_{max}} \delta @f$ */ Real beta2 = beta * beta; Real normal_open_norm = opening.dot(normal); Vector<Real> op_n_n(spatial_dimension); op_n_n = normal; op_n_n *= (1 - beta2); op_n_n *= normal_open_norm; tract = beta2 * opening; tract += op_n_n; delta_max_new = std::max(delta_max, delta); tract *= exp(1) * sigma_c * exp(-delta_max_new / delta_c) / delta_c; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCompressiveTraction( Vector<Real> & tract, const Vector<Real> & normal, Real delta_n, __attribute__((unused)) const Vector<Real> & opening) { Vector<Real> temp_tract(normal); if (exp_penalty) { temp_tract *= delta_n * exp(1) * sigma_c * exp(-delta_n / delta_c) / delta_c; } else { Real initial_tg = contact_tangent * exp(1) * sigma_c * delta_n / delta_c; temp_tract *= initial_tg; } tract += temp_tract; } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::matrix_iterator tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); - Array<Real>::const_vector_iterator normal_it = + auto normal_it = normal.begin(spatial_dimension); - Array<Real>::vector_iterator opening_it = + auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::iterator<Real> delta_max_it = + auto delta_max_it = delta_max.previous(el_type, ghost_type).begin(); Real beta2 = beta * beta; /** * compute tangent matrix @f$ \frac{\partial \mathbf{t}} * {\partial \delta} = \hat{\mathbf{t}} \otimes * \frac{\partial (t/\delta)}{\partial \delta} * \frac{\hat{\mathbf{t}}}{\delta}+ \frac{t}{\delta} [ \beta^2 \mathbf{I} + * (1-\beta^2) (\mathbf{n} \otimes \mathbf{n})] @f$ **/ /** * In which @f$ * \frac{\partial(t/ \delta)}{\partial \delta} = * \left\{\begin{array} {l l} * -e \frac{\sigma_c}{\delta_c^2 }e^{-\delta / \delta_c} & \quad if * \delta \geq \delta_{max} \\ * 0 & \quad if \delta < \delta_{max}, \delta_n > 0 * \end{array}\right. @f$ **/ for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++delta_max_it) { Real normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening(spatial_dimension); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; Vector<Real> tangential_opening(spatial_dimension); tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); Real delta = tangential_opening_norm; delta *= delta * beta2; delta += normal_opening_norm * normal_opening_norm; delta = sqrt(delta); if ((normal_opening_norm < 0) && (std::abs(normal_opening_norm) > Math::getTolerance())) { Vector<Real> op_n(*normal_it); op_n *= normal_opening_norm; Vector<Real> delta_s(*opening_it); delta_s -= op_n; delta = tangential_opening_norm * beta; computeCoupledTangent(*tangent_it, *normal_it, delta, delta_s, *delta_max_it); computeCompressivePenalty(*tangent_it, *normal_it, normal_opening_norm); } else computeCoupledTangent(*tangent_it, *normal_it, delta, *opening_it, *delta_max_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCoupledTangent( Matrix<Real> & tangent, const Vector<Real> & normal, Real delta, const Vector<Real> & opening, Real) { AKANTU_DEBUG_IN(); Real beta2 = beta * beta; Matrix<Real> J(spatial_dimension, spatial_dimension); J.eye(beta2); if (std::abs(delta) < Math::getTolerance()) { delta = Math::getTolerance(); } Real opening_normal; opening_normal = opening.dot(normal); Vector<Real> delta_e(normal); delta_e *= opening_normal; delta_e *= (1 - beta2); delta_e += (beta2 * opening); Real exponent = exp(1 - delta / delta_c) * sigma_c / delta_c; Matrix<Real> first_term(spatial_dimension, spatial_dimension); first_term.outerProduct(normal, normal); first_term *= (1 - beta2); first_term += J; Matrix<Real> second_term(spatial_dimension, spatial_dimension); second_term.outerProduct(delta_e, delta_e); second_term /= delta; second_term /= delta_c; Matrix<Real> diff(first_term); diff -= second_term; tangent = diff; tangent *= exponent; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveExponential<spatial_dimension>::computeCompressivePenalty( Matrix<Real> & tangent, const Vector<Real> & normal, Real delta_n) { if (!exp_penalty) delta_n = 0; Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(normal, normal); Real normal_tg = contact_tangent * exp(1) * sigma_c * exp(-delta_n / delta_c) * (1 - delta_n / delta_c) / delta_c; n_outer_n *= normal_tg; tangent += n_outer_n; } INSTANTIATE_MATERIAL(cohesive_exponential, MaterialCohesiveExponential); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc index 5780ec6e0..06bd8aff0 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc @@ -1,651 +1,650 @@ /** * @file material_cohesive_linear.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Feb 22 2012 * @date last modification: Thu Jan 14 2016 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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 <algorithm> #include <numeric> /* -------------------------------------------------------------------------- */ #include "dof_synchronizer.hh" #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinear<spatial_dimension>::MaterialCohesiveLinear( SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model, id), sigma_c_eff("sigma_c_eff", *this), delta_c_eff("delta_c_eff", *this), insertion_stress("insertion_stress", *this), opening_prec("opening_prec", *this), reduction_penalty("reduction_penalty", *this) { AKANTU_DEBUG_IN(); this->registerParam("beta", beta, Real(0.), _pat_parsable | _pat_readable, "Beta parameter"); this->registerParam("G_c", G_c, Real(0.), _pat_parsable | _pat_readable, "Mode I fracture energy"); this->registerParam("penalty", penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty coefficient"); this->registerParam("volume_s", volume_s, Real(0.), _pat_parsable | _pat_readable, "Reference volume for sigma_c scaling"); this->registerParam("m_s", m_s, Real(1.), _pat_parsable | _pat_readable, "Weibull exponent for sigma_c scaling"); this->registerParam("kappa", kappa, Real(1.), _pat_parsable | _pat_readable, "Kappa parameter"); this->registerParam( "contact_after_breaking", contact_after_breaking, false, _pat_parsable | _pat_readable, "Activation of contact when the elements are fully damaged"); this->registerParam("max_quad_stress_insertion", max_quad_stress_insertion, false, _pat_parsable | _pat_readable, "Insertion of cohesive element when stress is high " "enough just on one quadrature point"); this->registerParam("recompute", recompute, false, _pat_parsable | _pat_modifiable, "recompute solution"); this->use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); /// compute scalars beta2_kappa2 = beta * beta / kappa / kappa; beta2_kappa = beta * beta / kappa; if (Math::are_float_equal(beta, 0)) beta2_inv = 0; else beta2_inv = 1. / beta / beta; sigma_c_eff.initialize(1); delta_c_eff.initialize(1); insertion_stress.initialize(spatial_dimension); opening_prec.initialize(spatial_dimension); reduction_penalty.initialize(1); if (!Math::are_float_equal(delta_c, 0.)) delta_c_eff.setDefaultValue(delta_c); else delta_c_eff.setDefaultValue(2 * G_c / sigma_c); if (model->getIsExtrinsic()) scaleInsertionTraction(); opening_prec.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::scaleInsertionTraction() { AKANTU_DEBUG_IN(); // do nothing if volume_s hasn't been specified by the user if (Math::are_float_equal(volume_s, 0.)) return; const Mesh & mesh_facets = model->getMeshFacets(); - const FEEngine & fe_engine = model->getFEEngine(); - const FEEngine & fe_engine_facet = model->getFEEngine("FacetsFEEngine"); + const auto & fe_engine = model->getFEEngine(); + const auto & fe_engine_facet = model->getFEEngine("FacetsFEEngine"); // loop over facet type - Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1); - Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1); + auto first = mesh_facets.firstType(spatial_dimension - 1); + auto last = mesh_facets.lastType(spatial_dimension - 1); Real base_sigma_c = sigma_c; for (; first != last; ++first) { ElementType type_facet = *first; const Array<std::vector<Element>> & facet_to_element = mesh_facets.getElementToSubelement(type_facet); UInt nb_facet = facet_to_element.size(); UInt nb_quad_per_facet = fe_engine_facet.getNbIntegrationPoints(type_facet); // iterator to modify sigma_c for all the quadrature points of a facet - Array<Real>::vector_iterator sigma_c_iterator = + auto sigma_c_iterator = sigma_c(type_facet).begin_reinterpret(nb_quad_per_facet, nb_facet); for (UInt f = 0; f < nb_facet; ++f, ++sigma_c_iterator) { const std::vector<Element> & element_list = facet_to_element(f); // compute bounding volume Real volume = 0; auto elem = element_list.begin(); auto elem_end = element_list.end(); for (; elem != elem_end; ++elem) { if (*elem == ElementNull) continue; // unit vector for integration in order to obtain the volume UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(elem->type); Vector<Real> unit_vector(nb_quadrature_points, 1); volume += fe_engine.integrate(unit_vector, elem->type, elem->element, elem->ghost_type); } // scale sigma_c *sigma_c_iterator -= base_sigma_c; *sigma_c_iterator *= std::pow(volume_s / volume, 1. / m_s); *sigma_c_iterator += base_sigma_c; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkInsertion( bool check_only) { AKANTU_DEBUG_IN(); const Mesh & mesh_facets = model->getMeshFacets(); CohesiveElementInserter & inserter = model->getElementInserter(); for (auto && type_facet : mesh_facets.elementTypes(spatial_dimension - 1)) { ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); - const Array<bool> & facets_check = inserter.getCheckFacets(type_facet); + const auto & facets_check = inserter.getCheckFacets(type_facet); auto & f_insertion = inserter.getInsertionFacets(type_facet); auto & f_filter = facet_filter(type_facet); auto & sig_c_eff = sigma_c_eff(type_cohesive); auto & del_c = delta_c_eff(type_cohesive); auto & ins_stress = insertion_stress(type_cohesive); auto & trac_old = tractions.previous(type_cohesive); auto & open_prec = opening_prec(type_cohesive); auto & red_penalty = reduction_penalty(type_cohesive); const auto & f_stress = model->getStressOnFacets(type_facet); const auto & sigma_lim = sigma_c(type_facet); Real max_ratio = 0.; UInt index_f = 0; UInt index_filter = 0; UInt nn = 0; UInt nb_quad_facet = model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); UInt nb_quad_cohesive = model->getFEEngine("CohesiveFEEngine") .getNbIntegrationPoints(type_cohesive); AKANTU_DEBUG_ASSERT(nb_quad_cohesive == nb_quad_facet, "The cohesive element and the corresponding facet do " "not have the same numbers of integration points"); UInt nb_facet = f_filter.size(); // if (nb_facet == 0) continue; auto sigma_lim_it = sigma_lim.begin(); Matrix<Real> stress_tmp(spatial_dimension, spatial_dimension); Matrix<Real> normal_traction(spatial_dimension, nb_quad_facet); Vector<Real> stress_check(nb_quad_facet); UInt sp2 = spatial_dimension * spatial_dimension; const auto & tangents = model->getTangents(type_facet); const auto & normals = model->getFEEngine("FacetsFEEngine") .getNormalsOnIntegrationPoints(type_facet); auto normal_begin = normals.begin(spatial_dimension); auto tangent_begin = tangents.begin(tangents.getNbComponent()); auto facet_stress_begin = f_stress.begin(spatial_dimension, spatial_dimension * 2); std::vector<Real> new_sigmas; std::vector<Vector<Real>> new_normal_traction; std::vector<Real> new_delta_c; // loop over each facet belonging to this material for (UInt f = 0; f < nb_facet; ++f, ++sigma_lim_it) { UInt facet = f_filter(f); // skip facets where check shouldn't be realized if (!facets_check(facet)) continue; // compute the effective norm on each quadrature point of the facet for (UInt q = 0; q < nb_quad_facet; ++q) { UInt current_quad = facet * nb_quad_facet + q; const Vector<Real> & normal = normal_begin[current_quad]; const Vector<Real> & tangent = tangent_begin[current_quad]; const Matrix<Real> & facet_stress_it = facet_stress_begin[current_quad]; // compute average stress on the current quadrature point Matrix<Real> stress_1(facet_stress_it.storage(), spatial_dimension, spatial_dimension); Matrix<Real> stress_2(facet_stress_it.storage() + sp2, spatial_dimension, spatial_dimension); stress_tmp.copy(stress_1); stress_tmp += stress_2; stress_tmp /= 2.; Vector<Real> normal_traction_vec(normal_traction(q)); // compute normal and effective stress stress_check(q) = computeEffectiveNorm(stress_tmp, normal, tangent, normal_traction_vec); } // verify if the effective stress overcomes the threshold Real final_stress = stress_check.mean(); if (max_quad_stress_insertion) final_stress = *std::max_element( stress_check.storage(), stress_check.storage() + nb_quad_facet); if (final_stress > *sigma_lim_it) { if (model->isDefaultSolverExplicit()) { f_insertion(facet) = true; if (check_only) continue; // store the new cohesive material parameters for each quadrature // point for (UInt q = 0; q < nb_quad_facet; ++q) { Real new_sigma = stress_check(q); Vector<Real> normal_traction_vec(normal_traction(q)); if (spatial_dimension != 3) normal_traction_vec *= -1.; new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; // set delta_c in function of G_c or a given delta_c value if (Math::are_float_equal(delta_c, 0.)) new_delta = 2 * G_c / new_sigma; else new_delta = (*sigma_lim_it) / new_sigma * delta_c; new_delta_c.push_back(new_delta); } } else { Real ratio = final_stress / (*sigma_lim_it); if (ratio > max_ratio) { ++nn; max_ratio = ratio; index_f = f; index_filter = f_filter(f); } } } } /// Insertion of only 1 cohesive element in case of implicit approach. The /// one subjected to the highest stress. if (!model->isDefaultSolverExplicit()) { const Communicator & comm = model->getMesh().getCommunicator(); Array<Real> abs_max(comm.getNbProc()); abs_max(comm.whoAmI()) = max_ratio; comm.allGather(abs_max); auto it = std::max_element(abs_max.begin(), abs_max.end()); Int pos = it - abs_max.begin(); if (pos != comm.whoAmI()) { AKANTU_DEBUG_OUT(); return; } if (nn) { f_insertion(index_filter) = true; if (!check_only) { // Array<Real>::iterator<Matrix<Real> > normal_traction_it = // normal_traction.begin_reinterpret(nb_quad_facet, // spatial_dimension, nb_facet); - Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin(); + auto sigma_lim_it = sigma_lim.begin(); for (UInt q = 0; q < nb_quad_cohesive; ++q) { Real new_sigma = (sigma_lim_it[index_f]); Vector<Real> normal_traction_vec(spatial_dimension, 0.0); new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; // set delta_c in function of G_c or a given delta_c value if (!Math::are_float_equal(delta_c, 0.)) new_delta = delta_c; else new_delta = 2 * G_c / (new_sigma); new_delta_c.push_back(new_delta); } } } } // update material data for the new elements UInt old_nb_quad_points = sig_c_eff.size(); UInt new_nb_quad_points = new_sigmas.size(); sig_c_eff.resize(old_nb_quad_points + new_nb_quad_points); ins_stress.resize(old_nb_quad_points + new_nb_quad_points); trac_old.resize(old_nb_quad_points + new_nb_quad_points); del_c.resize(old_nb_quad_points + new_nb_quad_points); open_prec.resize(old_nb_quad_points + new_nb_quad_points); red_penalty.resize(old_nb_quad_points + new_nb_quad_points); for (UInt q = 0; q < new_nb_quad_points; ++q) { sig_c_eff(old_nb_quad_points + q) = new_sigmas[q]; del_c(old_nb_quad_points + q) = new_delta_c[q]; red_penalty(old_nb_quad_points + q) = false; for (UInt dim = 0; dim < spatial_dimension; ++dim) { ins_stress(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); trac_old(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); open_prec(old_nb_quad_points + q, dim) = 0.; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); /// opening_prec is the opening of the previous step in the /// Newton-Raphson loop auto opening_prec_it = opening_prec(el_type, ghost_type).begin(spatial_dimension); auto contact_traction_it = contact_tractions(el_type, ghost_type).begin(spatial_dimension); auto contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto traction_end = tractions(el_type, ghost_type).end(spatial_dimension); auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); auto delta_max_it = delta_max(el_type, ghost_type).begin(); - auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto damage_it = damage(el_type, ghost_type).begin(); auto insertion_stress_it = insertion_stress(el_type, ghost_type).begin(spatial_dimension); auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); if (!this->model->isDefaultSolverExplicit()) this->delta_max(el_type, ghost_type) .copy(this->delta_max.previous(el_type, ghost_type)); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++opening_prec_it, ++normal_it, ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, - ++delta_max_prev_it, ++reduction_penalty_it) { + ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; this->computeTractionOnQuad( - *traction_it, *delta_max_it, *delta_max_prev_it, *delta_c_it, - *insertion_stress_it, *sigma_c_it, *opening_it, *opening_prec_it, - *normal_it, normal_opening, tangential_opening, normal_opening_norm, - tangential_opening_norm, *damage_it, penetration, *reduction_penalty_it, - current_penalty, *contact_traction_it, *contact_opening_it); + *traction_it, *opening_it, *opening_prec_it, *normal_it, *delta_max_it, + *delta_c_it, *insertion_stress_it, *sigma_c_it, normal_opening, + tangential_opening, normal_opening_norm, tangential_opening_norm, + *damage_it, penetration, *reduction_penalty_it, current_penalty, + *contact_traction_it, *contact_opening_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkDeltaMax( GhostType ghost_type) { AKANTU_DEBUG_IN(); /** * This function set a predefined value to the parameter * delta_max_prev of the elements that have been inserted in the * last loading step for which convergence has not been * reached. This is done before reducing the loading and re-doing * the step. Otherwise, the updating of delta_max_prev would be * done with reference to the non-convergent solution. In this * function also other variables related to the contact and * friction behavior are correctly set. */ Mesh & mesh = fem_cohesive.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); /** * the variable "recompute" is set to true to activate the * procedure that reduce the penalty parameter for * compression. This procedure is set true only during the phase of * load_reduction, that has to be set in the maiin file. The * penalty parameter will be reduced only for the elements having * reduction_penalty = true. */ recompute = true; for (; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; ElementType el_type = *it; /// define iterators auto delta_max_it = delta_max(el_type, ghost_type).begin(); auto delta_max_end = delta_max(el_type, ghost_type).end(); auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto opening_prec_it = opening_prec(el_type, ghost_type).begin(spatial_dimension); auto opening_prec_prev_it = opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); /// loop on each quadrature point for (; delta_max_it != delta_max_end; ++delta_max_it, ++delta_max_prev_it, ++delta_c_it, ++opening_prec_it, ++opening_prec_prev_it) { if (*delta_max_prev_it == 0) /// elements inserted in the last incremental step, that did /// not converge *delta_max_it = *delta_c_it / 1000; else /// elements introduced in previous incremental steps, for /// which a correct value of delta_max_prev already exists *delta_max_it = *delta_max_prev_it; /// in case convergence is not reached, set opening_prec to the /// value referred to the previous incremental step *opening_prec_it = *opening_prec_prev_it; } } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::resetVariables( GhostType ghost_type) { AKANTU_DEBUG_IN(); /** * This function set the variables "recompute" and * "reduction_penalty" to false. It is called by solveStepCohesive * when convergence is reached. Such variables, in fact, have to be * false at the beginning of a new incremental step. */ Mesh & mesh = fem_cohesive.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); recompute = false; for (; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; ElementType el_type = *it; auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); auto reduction_penalty_end = reduction_penalty(el_type, ghost_type).end(); /// loop on each quadrature point for (; reduction_penalty_it != reduction_penalty_end; ++reduction_penalty_it) { *reduction_penalty_it = false; } } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); auto tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); /// NB: delta_max_it points on delta_max_previous, i.e. the /// delta_max related to the solution of the previous incremental /// step auto delta_max_it = delta_max.previous(el_type, ghost_type).begin(); auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto damage_it = damage(el_type, ghost_type).begin(); auto contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it, ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; this->computeTangentTractionOnQuad( *tangent_it, *delta_max_it, *delta_c_it, *sigma_c_it, *opening_it, *normal_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *reduction_penalty_it, current_penalty, *contact_opening_it); // check if the tangential stiffness matrix is symmetric // for (UInt h = 0; h < spatial_dimension; ++h){ // for (UInt l = h; l < spatial_dimension; ++l){ // if (l > h){ // Real k_ls = (*tangent_it)[spatial_dimension*h+l]; // Real k_us = (*tangent_it)[spatial_dimension*l+h]; // // std::cout << "k_ls = " << k_ls << std::endl; // // std::cout << "k_us = " << k_us << std::endl; // if (std::abs(k_ls) > 1e-13 && std::abs(k_us) > 1e-13){ // Real error = std::abs((k_ls - k_us) / k_us); // if (error > 1e-10){ // std::cout << "non symmetric cohesive matrix" << std::endl; // // std::cout << "error " << error << std::endl; // } // } // } // } // } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear, MaterialCohesiveLinear); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh index f298b4a96..038db7968 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.hh @@ -1,212 +1,206 @@ /** * @file material_cohesive_linear.hh * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Jan 14 2016 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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_cohesive.hh" /* -------------------------------------------------------------------------- */ - #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ namespace akantu { /** * Cohesive material linear damage for extrinsic case * * parameters in the material files : * - sigma_c : critical stress sigma_c (default: 0) - * - beta : weighting parameter for sliding and normal opening (default: 0) + * - beta : weighting parameter for sliding and normal opening (default: + * 0) * - G_cI : fracture energy for mode I (default: 0) * - G_cII : fracture energy for mode II (default: 0) * - penalty : stiffness in compression to prevent penetration */ -template<UInt spatial_dimension> +template <UInt spatial_dimension> class MaterialCohesiveLinear : public MaterialCohesive { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - /// initialize the material parameters void initMaterial() override; /// check stress for cohesive elements' insertion void checkInsertion(bool check_only = false) override; /// compute effective stress norm for insertion check Real computeEffectiveNorm(const Matrix<Real> & stress, - const Vector<Real> & normal, - const Vector<Real> & tangent, - Vector<Real> & normal_stress) const; + const Vector<Real> & normal, + const Vector<Real> & tangent, + Vector<Real> & normal_stress) const; protected: - /// constitutive law void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override; /// check delta_max for cohesive elements in case of no convergence /// in the solveStep (only for extrinsic-implicit) void checkDeltaMax(GhostType ghost_type = _not_ghost) override; /// reset variables when convergence is reached (only for /// extrinsic-implicit) void resetVariables(GhostType ghost_type = _not_ghost) override; /// compute tangent stiffness matrix void computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) override; /** * Scale insertion traction sigma_c according to the volume of the * two elements surrounding a facet * * see the article: F. Zhou and J. F. Molinari "Dynamic crack * propagation with cohesive elements: a methodology to address mesh * dependency" International Journal for Numerical Methods in * Engineering (2004) */ void scaleInsertionTraction(); /// compute the traction for a given quadrature point - inline void computeTractionOnQuad(Vector<Real> & traction, Real & delta_max, - const Real & delta_max_prev, const Real & delta_c, - const Vector<Real> & insertion_stress, const Real & sigma_c, - Vector<Real> & opening, Vector<Real> & opening_prec, const Vector<Real> & normal, - Vector<Real> & normal_opening, Vector<Real> & tangential_opening, - Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, - bool & penetration, bool & reduction_penalty, Real & current_penalty, - Vector<Real> & contact_traction, Vector<Real> & contact_opening); - - inline void computeTangentTractionOnQuad(Matrix<Real> & tangent, - Real & delta_max, const Real & delta_c, - const Real & sigma_c, - Vector<Real> & opening, const Vector<Real> & normal, - Vector<Real> & normal_opening, Vector<Real> & tangential_opening, - Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, - bool & penetration, bool & reduction_penalty, Real & current_penalty, - Vector<Real> & contact_opening); + inline void computeTractionOnQuad( + Vector<Real> & traction, Vector<Real> & opening, + Vector<Real> & opening_prec, const Vector<Real> & normal, + Real & delta_max, const Real & delta_c, + const Vector<Real> & insertion_stress, const Real & sigma_c, + Vector<Real> & normal_opening, Vector<Real> & tangential_opening, + Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, + bool & penetration, bool & reduction_penalty, Real & current_penalty, + Vector<Real> & contact_traction, Vector<Real> & contact_opening); + + inline void computeTangentTractionOnQuad( + Matrix<Real> & tangent, Real & delta_max, const Real & delta_c, + const Real & sigma_c, Vector<Real> & opening, const Vector<Real> & normal, + Vector<Real> & normal_opening, Vector<Real> & tangential_opening, + Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, + bool & penetration, bool & reduction_penalty, Real & current_penalty, + Vector<Real> & contact_opening); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: - /// get sigma_c_eff AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(InsertionTraction, sigma_c_eff, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// beta parameter Real beta; /// beta square inverse to compute effective norm Real beta2_inv; /// mode I fracture energy Real G_c; /// kappa parameter Real kappa; /// constitutive law scalar to compute delta Real beta2_kappa2; /// constitutive law scalar to compute traction Real beta2_kappa; /// penalty coefficient Real penalty; /// reference volume used to scale sigma_c Real volume_s; /// weibull exponent used to scale sigma_c Real m_s; /// variable defining if we are recomputing the last loading step /// after load_reduction bool recompute; /// critical effective stress RandomInternalField<Real, CohesiveInternalField> sigma_c_eff; /// effective critical displacement (each element can have a /// different value) CohesiveInternalField<Real> delta_c_eff; /// stress at insertion CohesiveInternalField<Real> insertion_stress; /// delta of the previous step CohesiveInternalField<Real> opening_prec; /** * variable that defines if the penalty parameter for compression * has to be decreased for problems of convergence in the solution * loops */ CohesiveInternalField<bool> reduction_penalty; /// variable saying if there should be penalty contact also after /// breaking the cohesive elements bool contact_after_breaking; /// insertion of cohesive element when stress is high enough just on /// one quadrature point bool max_quad_stress_insertion; - }; - /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ } // akantu #include "material_cohesive_linear_inline_impl.cc" #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc index aeffe864e..e38bd4c1b 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_fatigue.cc @@ -1,296 +1,296 @@ /** * @file material_cohesive_linear_fatigue.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Feb 20 2015 * @date last modification: Tue Jan 12 2016 * * @brief See material_cohesive_linear_fatigue.hh for information * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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_cohesive_linear_fatigue.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinearFatigue<spatial_dimension> ::MaterialCohesiveLinearFatigue(SolidMechanicsModel & model, const ID & id) : MaterialCohesiveLinear<spatial_dimension>(model, id), delta_prec("delta_prec", *this), K_plus("K_plus", *this), K_minus("K_minus", *this), T_1d("T_1d", *this), switches("switches", *this), delta_dot_prec("delta_dot_prec", *this), normal_regime("normal_regime", *this) { this->registerParam("delta_f", delta_f, Real(-1.) , _pat_parsable | _pat_readable, "delta_f"); this->registerParam("progressive_delta_f", progressive_delta_f, false, _pat_parsable | _pat_readable, "Whether or not delta_f is equal to delta_max"); this->registerParam("count_switches", count_switches, false, _pat_parsable | _pat_readable, "Count the opening/closing switches per element"); this->registerParam("fatigue_ratio", fatigue_ratio, Real(1.), _pat_parsable | _pat_readable, "What portion of the cohesive law is subjected to fatigue"); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFatigue<spatial_dimension>::initMaterial() { MaterialCohesiveLinear<spatial_dimension>::initMaterial(); // check that delta_f has a proper value or assign a defaul value if (delta_f < 0) delta_f = this->delta_c_eff; else if (delta_f < this->delta_c_eff) AKANTU_ERROR("Delta_f must be greater or equal to delta_c"); delta_prec.initialize(1); K_plus.initialize(1); K_minus.initialize(1); T_1d.initialize(1); normal_regime.initialize(1); if (count_switches) { switches.initialize(1); delta_dot_prec.initialize(1); } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinearFatigue<spatial_dimension> ::computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators - Array<Real>::vector_iterator traction_it = + auto traction_it = this->tractions(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator opening_it = + auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator contact_traction_it = + auto contact_traction_it = this->contact_tractions(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator contact_opening_it = + auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::const_vector_iterator normal_it = normal.begin(spatial_dimension); + auto normal_it = normal.begin(spatial_dimension); - Array<Real>::vector_iterator traction_end = + auto traction_end = this->tractions(el_type, ghost_type).end(spatial_dimension); const Array<Real> & sigma_c_array = this->sigma_c_eff(el_type, ghost_type); Array<Real> & delta_max_array = this->delta_max(el_type, ghost_type); const Array<Real> & delta_c_array = this->delta_c_eff(el_type, ghost_type); Array<Real> & damage_array = this->damage(el_type, ghost_type); - Array<Real>::vector_iterator insertion_stress_it = + auto insertion_stress_it = this->insertion_stress(el_type, ghost_type).begin(spatial_dimension); Array<Real> & delta_prec_array = delta_prec(el_type, ghost_type); Array<Real> & K_plus_array = K_plus(el_type, ghost_type); Array<Real> & K_minus_array = K_minus(el_type, ghost_type); Array<Real> & T_1d_array = T_1d(el_type, ghost_type); Array<bool> & normal_regime_array = normal_regime(el_type, ghost_type); Array<UInt> * switches_array = nullptr; Array<Real> * delta_dot_prec_array = nullptr; if (count_switches) { switches_array = &switches(el_type, ghost_type); delta_dot_prec_array = &delta_dot_prec(el_type, ghost_type); } auto * memory_space = new Real[2 * spatial_dimension]; Vector<Real> normal_opening(memory_space, spatial_dimension); Vector<Real> tangential_opening(memory_space + spatial_dimension, spatial_dimension); Real tolerance = Math::getTolerance(); /// loop on each quadrature point for (UInt q = 0; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, ++q) { /// compute normal and tangential opening vectors Real normal_opening_norm = opening_it->dot(*normal_it); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \frac{\beta^2}{\kappa^2} \Delta_t^2 + \Delta_n^2 } @f$ */ Real delta = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; bool penetration = normal_opening_norm < -tolerance; if (this->contact_after_breaking == false && Math::are_float_equal(damage_array(q), 1.)) penetration = false; if (penetration) { /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= this->penalty; *contact_opening_it = normal_opening; /// don't consider penetration contribution for delta *opening_it = tangential_opening; normal_opening.clear(); } else { delta += normal_opening_norm * normal_opening_norm; contact_traction_it->clear(); contact_opening_it->clear(); } delta = std::sqrt(delta); /** * Compute traction @f$ \mathbf{T} = \left( * \frac{\beta^2}{\kappa} \Delta_t \mathbf{t} + \Delta_n * \mathbf{n} \right) \frac{\sigma_c}{\delta} \left( 1- * \frac{\delta}{\delta_c} \right)@f$ */ // update maximum displacement and damage delta_max_array(q) = std::max(delta, delta_max_array(q)); damage_array(q) = std::min(delta_max_array(q) / delta_c_array(q), Real(1.)); Real delta_dot = delta - delta_prec_array(q); // count switches if asked if (count_switches) { if ( (delta_dot > 0. && (*delta_dot_prec_array)(q) <= 0.) || (delta_dot < 0. && (*delta_dot_prec_array)(q) >= 0.) ) ++((*switches_array)(q)); (*delta_dot_prec_array)(q) = delta_dot; } // set delta_f equal to delta_max if desired if (progressive_delta_f) delta_f = delta_max_array(q); // broken element case if (Math::are_float_equal(damage_array(q), 1.)) traction_it->clear(); // just inserted element case else if (Math::are_float_equal(damage_array(q), 0.)) { if (penetration) traction_it->clear(); else *traction_it = *insertion_stress_it; // initialize the 1d traction to sigma_c T_1d_array(q) = sigma_c_array(q); } // normal case else { // if element is closed then there are zero tractions if (delta <= tolerance) traction_it->clear(); // otherwise compute new tractions if the new delta is different // than the previous one else if (std::abs(delta_dot) > tolerance) { // loading case if (delta_dot > 0.) { if (!normal_regime_array(q)) { // equation (4) of the article K_plus_array(q) *= 1. - delta_dot / delta_f; // equivalent to equation (2) of the article T_1d_array(q) += K_plus_array(q) * delta_dot; // in case of reloading, traction must not exceed that of the // envelop of the cohesive law Real max_traction = sigma_c_array(q) * (1 - delta / delta_c_array(q)); bool max_traction_exceeded = T_1d_array(q) > max_traction; if (max_traction_exceeded) T_1d_array(q) = max_traction; // switch to standard linear cohesive law if (delta_max_array(q) > fatigue_ratio * delta_c_array(q)) { // reset delta_max to avoid big jumps in the traction delta_max_array(q) = sigma_c_array(q) / (T_1d_array(q) / delta + sigma_c_array(q) / delta_c_array(q)); damage_array(q) = std::min(delta_max_array(q) / delta_c_array(q), Real(1.)); K_minus_array(q) = sigma_c_array(q) / delta_max_array(q) * (1. - damage_array(q)); normal_regime_array(q) = true; } else { // equation (3) of the article K_minus_array(q) = T_1d_array(q) / delta; // if the traction is following the cohesive envelop, then // K_plus has to be reset if (max_traction_exceeded) K_plus_array(q) = K_minus_array(q); } } else { // compute stiffness according to the standard law K_minus_array(q) = sigma_c_array(q) / delta_max_array(q) * (1. - damage_array(q)); } } // unloading case else if (!normal_regime_array(q)) { // equation (4) of the article K_plus_array(q) += (K_plus_array(q) - K_minus_array(q)) * delta_dot / delta_f; // equivalent to equation (2) of the article T_1d_array(q) = K_minus_array(q) * delta; } // applying the actual stiffness *traction_it = tangential_opening; *traction_it *= this->beta2_kappa; *traction_it += normal_opening; *traction_it *= K_minus_array(q); } } // update precendent delta delta_prec_array(q) = delta; } delete [] memory_space; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear_fatigue, MaterialCohesiveLinearFatigue); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc index 748481c51..0fe8e55af 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc @@ -1,386 +1,356 @@ /** * @file material_cohesive_linear_friction.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * * @date creation: Tue Jan 12 2016 * @date last modification: Thu Jan 14 2016 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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_cohesive_linear_friction.hh" #include "solid_mechanics_model_cohesive.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinearFriction<spatial_dimension>:: MaterialCohesiveLinearFriction(SolidMechanicsModel & model, const ID & id) : MaterialParent(model, id), residual_sliding("residual_sliding", *this), friction_force("friction_force", *this) { AKANTU_DEBUG_IN(); this->registerParam("mu", mu_max, Real(0.), _pat_parsable | _pat_readable, "Maximum value of the friction coefficient"); this->registerParam("penalty_for_friction", friction_penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty parameter for the friction behavior"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFriction<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialParent::initMaterial(); friction_force.initialize(spatial_dimension); residual_sliding.initialize(1); residual_sliding.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFriction<spatial_dimension>::computeTraction( __attribute__((unused)) const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); residual_sliding.resize(); friction_force.resize(); /// define iterators - Array<Real>::vector_iterator traction_it = + auto traction_it = this->tractions(el_type, ghost_type).begin(spatial_dimension); - - Array<Real>::vector_iterator traction_end = + auto traction_end = this->tractions(el_type, ghost_type).end(spatial_dimension); - - Array<Real>::vector_iterator opening_it = - this->opening(el_type, ghost_type).begin(spatial_dimension); + auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); /// opening_prec is the opening at the end of the previous step in /// the Newton-Raphson loop - Array<Real>::vector_iterator opening_prec_it = + auto opening_prec_it = this->opening_prec(el_type, ghost_type).begin(spatial_dimension); /// opening_prec_prev is the opening (opening + penetration) /// referred to the convergence of the previous incremental step - Array<Real>::vector_iterator opening_prec_prev_it = + auto opening_prec_prev_it = this->opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); - - Array<Real>::vector_iterator contact_traction_it = + auto contact_traction_it = this->contact_tractions(el_type, ghost_type).begin(spatial_dimension); - - Array<Real>::vector_iterator contact_opening_it = + auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); Array<Real>::const_iterator<Vector<Real>> normal_it = this->normal.begin(spatial_dimension); - Array<Real>::iterator<Real> sigma_c_it = - this->sigma_c_eff(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> delta_max_it = - this->delta_max(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> delta_max_prev_it = + auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); + auto delta_max_it = this->delta_max(el_type, ghost_type).begin(); + auto delta_max_prev_it = this->delta_max.previous(el_type, ghost_type).begin(); - Array<Real>::iterator<Real> delta_c_it = - this->delta_c_eff(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> damage_it = - this->damage(el_type, ghost_type).begin(); + auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); + auto damage_it = this->damage(el_type, ghost_type).begin(); - Array<Real>::vector_iterator insertion_stress_it = + auto insertion_stress_it = this->insertion_stress(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::iterator<Real> res_sliding_it = - this->residual_sliding(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> res_sliding_prev_it = + auto res_sliding_it = this->residual_sliding(el_type, ghost_type).begin(); + auto res_sliding_prev_it = this->residual_sliding.previous(el_type, ghost_type).begin(); - Array<Real>::vector_iterator friction_force_it = + auto friction_force_it = this->friction_force(el_type, ghost_type).begin(spatial_dimension); - Array<bool>::iterator<bool> reduction_penalty_it = + auto reduction_penalty_it = this->reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); if (!this->model->isDefaultSolverExplicit()) this->delta_max(el_type, ghost_type) .copy(this->delta_max.previous(el_type, ghost_type)); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++opening_prec_prev_it, ++opening_prec_it, ++normal_it, ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, ++delta_max_prev_it, ++res_sliding_it, ++res_sliding_prev_it, ++friction_force_it, ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; this->computeTractionOnQuad( - *traction_it, *delta_max_it, *delta_max_prev_it, *delta_c_it, - *insertion_stress_it, *sigma_c_it, *opening_it, *opening_prec_it, - *normal_it, normal_opening, tangential_opening, normal_opening_norm, - tangential_opening_norm, *damage_it, penetration, *reduction_penalty_it, - current_penalty, *contact_traction_it, *contact_opening_it); + *traction_it, *opening_it, *opening_prec_it, *normal_it, *delta_max_it, + *delta_c_it, *insertion_stress_it, *sigma_c_it, normal_opening, + tangential_opening, normal_opening_norm, tangential_opening_norm, + *damage_it, penetration, *reduction_penalty_it, current_penalty, + *contact_traction_it, *contact_opening_it); if (penetration) { /// the friction coefficient mu increases with the damage. It /// equals the maximum value when damage = 1. // Real damage = std::min(*delta_max_prev_it / *delta_c_it, // Real(1.)); Real mu = mu_max; // * damage; /// the definition of tau_max refers to the opening /// (penetration) of the previous incremental step Real normal_opening_prev_norm = std::min(opening_prec_prev_it->dot(*normal_it), Real(0.)); // Vector<Real> normal_opening_prev = (*normal_it); // normal_opening_prev *= normal_opening_prev_norm; Real tau_max = mu * current_penalty * (std::abs(normal_opening_prev_norm)); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); /// tau is the norm of the friction force, acting tangentially to the /// surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if ((tangential_opening_norm - *res_sliding_prev_it) < 0.0) tau = -tau; /// from tau get the x and y components of friction, to be added in the /// force vector Vector<Real> tangent_unit_vector(spatial_dimension); tangent_unit_vector = tangential_opening / tangential_opening_norm; *friction_force_it = tau * tangent_unit_vector; /// update residual_sliding *res_sliding_it = tangential_opening_norm - (std::abs(tau) / friction_penalty); } else { friction_force_it->clear(); } *traction_it += *friction_force_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFriction<spatial_dimension>::checkDeltaMax( GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialParent::checkDeltaMax(); Mesh & mesh = this->fem_cohesive.getMesh(); - Mesh::type_iterator it = - mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); - Mesh::type_iterator last_type = - mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); + auto it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); + auto last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); for (; it != last_type; ++it) { Array<UInt> & elem_filter = this->element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; ElementType el_type = *it; /// define iterators - Array<Real>::iterator<Real> delta_max_it = - this->delta_max(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> delta_max_end = - this->delta_max(el_type, ghost_type).end(); + auto delta_max_it = this->delta_max(el_type, ghost_type).begin(); + auto delta_max_end = this->delta_max(el_type, ghost_type).end(); - Array<Real>::iterator<Real> res_sliding_it = - this->residual_sliding(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> res_sliding_prev_it = + auto res_sliding_it = this->residual_sliding(el_type, ghost_type).begin(); + auto res_sliding_prev_it = this->residual_sliding.previous(el_type, ghost_type).begin(); /// loop on each quadrature point for (; delta_max_it != delta_max_end; ++delta_max_it, ++res_sliding_it, ++res_sliding_prev_it) { /** * in case convergence is not reached, set "residual_sliding" * for the friction behaviour to the value referred to the * previous incremental step */ *res_sliding_it = *res_sliding_prev_it; } } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearFriction<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, __attribute__((unused)) const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array<Real>::matrix_iterator tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); - Array<Real>::const_vector_iterator normal_it = - this->normal.begin(spatial_dimension); + auto normal_it = this->normal.begin(spatial_dimension); - Array<Real>::vector_iterator opening_it = - this->opening(el_type, ghost_type).begin(spatial_dimension); + auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator opening_prec_prev_it = + auto opening_prec_prev_it = this->opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); /** * NB: delta_max_it points on delta_max_previous, i.e. the * delta_max related to the solution of the previous incremental * step */ - Array<Real>::iterator<Real> delta_max_it = - this->delta_max.previous(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> sigma_c_it = - this->sigma_c_eff(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> delta_c_it = - this->delta_c_eff(el_type, ghost_type).begin(); - - Array<Real>::iterator<Real> damage_it = - this->damage(el_type, ghost_type).begin(); + auto delta_max_it = this->delta_max.previous(el_type, ghost_type).begin(); + auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); + auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); + auto damage_it = this->damage(el_type, ghost_type).begin(); - Array<Real>::iterator<Vector<Real>> contact_opening_it = + auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::iterator<Real> res_sliding_prev_it = + auto res_sliding_prev_it = this->residual_sliding.previous(el_type, ghost_type).begin(); - Array<bool>::iterator<bool> reduction_penalty_it = + auto reduction_penalty_it = this->reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++opening_prec_prev_it, ++delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it, ++res_sliding_prev_it, ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; this->computeTangentTractionOnQuad( *tangent_it, *delta_max_it, *delta_c_it, *sigma_c_it, *opening_it, *normal_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *reduction_penalty_it, current_penalty, *contact_opening_it); if (penetration) { // Real damage = std::min(*delta_max_it / *delta_c_it, Real(1.)); Real mu = mu_max; // * damage; Real normal_opening_prev_norm = std::min(opening_prec_prev_it->dot(*normal_it), Real(0.)); // Vector<Real> normal_opening_prev = (*normal_it); // normal_opening_prev *= normal_opening_prev_norm; Real tau_max = mu * current_penalty * (std::abs(normal_opening_prev_norm)); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); // tau is the norm of the friction force, acting tangentially to the // surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if (tau < tau_max && tau_max > Math::getTolerance()) { Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(1.); Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); Matrix<Real> nn(n_outer_n); I -= nn; *tangent_it += I * friction_penalty; } } // check if the tangential stiffness matrix is symmetric // for (UInt h = 0; h < spatial_dimension; ++h){ // for (UInt l = h; l < spatial_dimension; ++l){ // if (l > h){ // Real k_ls = (*tangent_it)[spatial_dimension*h+l]; // Real k_us = (*tangent_it)[spatial_dimension*l+h]; // // std::cout << "k_ls = " << k_ls << std::endl; // // std::cout << "k_us = " << k_us << std::endl; // if (std::abs(k_ls) > 1e-13 && std::abs(k_us) > 1e-13){ // Real error = std::abs((k_ls - k_us) / k_us); // if (error > 1e-10){ // std::cout << "non symmetric cohesive matrix" << std::endl; // // std::cout << "error " << error << std::endl; // } // } // } // } // } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear_friction, MaterialCohesiveLinearFriction); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc index e4bb60b53..593e961c4 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_inline_impl.cc @@ -1,319 +1,296 @@ /** * @file material_cohesive_linear_inline_impl.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Apr 22 2015 * @date last modification: Thu Jan 14 2016 * * @brief Inline functions of the MaterialCohesiveLinear * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_INLINE_IMPL_CC__ /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ -template<UInt dim> -inline Real MaterialCohesiveLinear<dim>::computeEffectiveNorm(const Matrix<Real> & stress, - const Vector<Real> & normal, - const Vector<Real> & tangent, - Vector<Real> & normal_traction) const { +template <UInt dim> +inline Real MaterialCohesiveLinear<dim>::computeEffectiveNorm( + const Matrix<Real> & stress, const Vector<Real> & normal, + const Vector<Real> & tangent, Vector<Real> & normal_traction) const { normal_traction.mul<false>(stress, normal); Real normal_contrib = normal_traction.dot(normal); /// in 3D tangential components must be summed Real tangent_contrib = 0; if (dim == 2) { Real tangent_contrib_tmp = normal_traction.dot(tangent); tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; - } - else if (dim == 3) { + } else if (dim == 3) { for (UInt s = 0; s < dim - 1; ++s) { const Vector<Real> tangent_v(tangent.storage() + s * dim, dim); Real tangent_contrib_tmp = normal_traction.dot(tangent_v); tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; } } tangent_contrib = std::sqrt(tangent_contrib); normal_contrib = std::max(Real(0.), normal_contrib); - return std::sqrt(normal_contrib * normal_contrib + tangent_contrib * tangent_contrib * beta2_inv); + return std::sqrt(normal_contrib * normal_contrib + + tangent_contrib * tangent_contrib * beta2_inv); } /* -------------------------------------------------------------------------- */ -template<UInt dim> +template <UInt dim> inline void MaterialCohesiveLinear<dim>::computeTractionOnQuad( - Vector<Real> & traction, - Real & delta_max, - __attribute__((unused)) const Real & delta_max_prev, - const Real & delta_c, - const Vector<Real> & insertion_stress, - const Real & sigma_c, - Vector<Real> & opening, - Vector<Real> & opening_prec, - const Vector<Real> & normal, - Vector<Real> & normal_opening, - Vector<Real> & tangential_opening, - Real & normal_opening_norm, - Real & tangential_opening_norm, - Real & damage, - bool & penetration, - bool & reduction_penalty, - Real & current_penalty, - Vector<Real> & contact_traction, - Vector<Real> & contact_opening) { + Vector<Real> & traction, Vector<Real> & opening, + Vector<Real> & opening_prec, const Vector<Real> & normal, Real & delta_max, + const Real & delta_c, const Vector<Real> & insertion_stress, + const Real & sigma_c, Vector<Real> & normal_opening, + Vector<Real> & tangential_opening, Real & normal_opening_norm, + Real & tangential_opening_norm, Real & damage, bool & penetration, + bool & reduction_penalty, Real & current_penalty, + Vector<Real> & contact_traction, Vector<Real> & contact_opening) { /// compute normal and tangential opening vectors normal_opening_norm = opening.dot(normal); - normal_opening = normal; + normal_opening = normal; normal_opening *= normal_opening_norm; - tangential_opening = opening; + tangential_opening = opening; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \frac{\beta^2}{\kappa^2} \Delta_t^2 + \Delta_n^2 } @f$ */ - Real delta = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; + Real delta = + tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm < 0.0; - if (this->contact_after_breaking == false && Math::are_float_equal(damage, 1.)) + if (this->contact_after_breaking == false && + Math::are_float_equal(damage, 1.)) penetration = false; - /** + /** * if during the convergence loop a cohesive element continues to * jumps from penetration to opening, and convergence is not * reached, its penalty parameter will be reduced in the * recomputation of the same incremental step. recompute is set * equal to true when convergence is not reached in the * solveStepCohesive function and the execution of the program * goes back to the main file where the variable load_reduction * is set equal to true. */ - + Real normal_opening_prec_norm = opening_prec.dot(normal); opening_prec = opening; if (!this->model->isDefaultSolverExplicit() && !this->recompute) if ((normal_opening_prec_norm * normal_opening_norm) < 0.0) { reduction_penalty = true; } if (penetration) { - if (this->recompute && reduction_penalty){ + if (this->recompute && reduction_penalty) { /// the penalty parameter is locally reduced current_penalty = this->penalty / 100.; - } - else + } else current_penalty = this->penalty; /// use penalty coefficient in case of penetration contact_traction = normal_opening; contact_traction *= current_penalty; contact_opening = normal_opening; /// don't consider penetration contribution for delta opening = tangential_opening; normal_opening.clear(); - } - else { + } else { delta += normal_opening_norm * normal_opening_norm; contact_traction.clear(); contact_opening.clear(); } delta = std::sqrt(delta); /// update maximum displacement and damage delta_max = std::max(delta_max, delta); damage = std::min(delta_max / delta_c, Real(1.)); /** * Compute traction @f$ \mathbf{T} = \left( * \frac{\beta^2}{\kappa} \Delta_t \mathbf{t} + \Delta_n * \mathbf{n} \right) \frac{\sigma_c}{\delta} \left( 1- * \frac{\delta}{\delta_c} \right)@f$ */ if (Math::are_float_equal(damage, 1.)) traction.clear(); else if (Math::are_float_equal(damage, 0.)) { if (penetration) traction.clear(); else traction = insertion_stress; - } - else { - traction = tangential_opening; + } else { + traction = tangential_opening; traction *= this->beta2_kappa; traction += normal_opening; AKANTU_DEBUG_ASSERT(delta_max != 0., - "Division by zero, tolerance might be too low"); + "Division by zero, tolerance might be too low"); traction *= sigma_c / delta_max * (1. - damage); } } - /* -------------------------------------------------------------------------- */ -template<UInt dim> +template <UInt dim> inline void MaterialCohesiveLinear<dim>::computeTangentTractionOnQuad( - Matrix<Real> & tangent, - Real & delta_max, - const Real & delta_c, - const Real & sigma_c, - Vector<Real> & opening, - const Vector<Real> & normal, - Vector<Real> & normal_opening, - Vector<Real> & tangential_opening, - Real & normal_opening_norm, - Real & tangential_opening_norm, - Real & damage, - bool & penetration, - bool & reduction_penalty, - Real & current_penalty, + Matrix<Real> & tangent, Real & delta_max, const Real & delta_c, + const Real & sigma_c, Vector<Real> & opening, const Vector<Real> & normal, + Vector<Real> & normal_opening, Vector<Real> & tangential_opening, + Real & normal_opening_norm, Real & tangential_opening_norm, Real & damage, + bool & penetration, bool & reduction_penalty, Real & current_penalty, Vector<Real> & contact_opening) { /** * During the update of the residual the interpenetrations are * stored in the array "contact_opening", therefore, in the case * of penetration, in the array "opening" there are only the * tangential components. */ opening += contact_opening; /// compute normal and tangential opening vectors normal_opening_norm = opening.dot(normal); normal_opening = normal; normal_opening *= normal_opening_norm; tangential_opening = opening; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); - Real delta = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; + Real delta = + tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm < 0.0; - if (this->contact_after_breaking == false && Math::are_float_equal(damage, 1.)) + if (this->contact_after_breaking == false && + Math::are_float_equal(damage, 1.)) penetration = false; Real derivative = 0; // derivative = d(t/delta)/ddelta Real t = 0; Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(normal, normal); - if (penetration){ + if (penetration) { if (this->recompute && reduction_penalty) current_penalty = this->penalty / 100.; else current_penalty = this->penalty; /// stiffness in compression given by the penalty parameter tangent += n_outer_n; tangent *= current_penalty; opening = tangential_opening; normal_opening_norm = opening.dot(normal); normal_opening = normal; normal_opening *= normal_opening_norm; - } - else{ + } else { delta += normal_opening_norm * normal_opening_norm; } delta = std::sqrt(delta); /** * Delta has to be different from 0 to have finite values of * tangential stiffness. At the element insertion, delta = * 0. Therefore, a fictictious value is defined, for the * evaluation of the first value of K. */ if (delta < Math::getTolerance()) delta = delta_c / 1000.; - if (delta >= delta_max){ - if (delta <= delta_c){ + if (delta >= delta_max) { + if (delta <= delta_c) { derivative = -sigma_c / (delta * delta); t = sigma_c * (1 - delta / delta_c); } else { derivative = 0.; t = 0.; } - } else if (delta < delta_max){ + } else if (delta < delta_max) { Real tmax = sigma_c * (1 - delta_max / delta_c); t = tmax / delta_max * delta; } - /// computation of the derivative of the constitutive law (dT/ddelta) Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(this->beta2_kappa); Matrix<Real> nn(n_outer_n); nn *= (1. - this->beta2_kappa); nn += I; - nn *= t/delta; + nn *= t / delta; Vector<Real> t_tilde(normal_opening); t_tilde *= (1. - this->beta2_kappa2); Vector<Real> mm(opening); mm *= this->beta2_kappa2; t_tilde += mm; Vector<Real> t_hat(normal_opening); t_hat += this->beta2_kappa * tangential_opening; Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(t_hat, t_tilde); - prov *= derivative/delta; + prov *= derivative / delta; prov += nn; Matrix<Real> prov_t = prov.transpose(); tangent += prov_t; } /* -------------------------------------------------------------------------- */ } // akantu /* -------------------------------------------------------------------------- */ #endif //__AKANTU_MATERIAL_COHESIVE_LINEAR_INLINE_IMPL_CC__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc index f24dd6900..e7b16ffe7 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_uncoupled.cc @@ -1,596 +1,596 @@ /** * @file material_cohesive_linear_uncoupled.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * * @date creation: Wed Feb 22 2012 * @date last modification: Thu Jan 14 2016 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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 <algorithm> #include <numeric> /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear_uncoupled.hh" #include "solid_mechanics_model_cohesive.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinearUncoupled<spatial_dimension>:: MaterialCohesiveLinearUncoupled(SolidMechanicsModel & model, const ID & id) : MaterialCohesiveLinear<spatial_dimension>(model, id), delta_n_max("delta_n_max", *this), delta_t_max("delta_t_max", *this), damage_n("damage_n", *this), damage_t("damage_t", *this) { AKANTU_DEBUG_IN(); this->registerParam( "roughness", R, Real(1.), _pat_parsable | _pat_readable, "Roughness to define coupling between mode II and mode I"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearUncoupled<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesiveLinear<spatial_dimension>::initMaterial(); delta_n_max.initialize(1); delta_t_max.initialize(1); damage_n.initialize(1); damage_t.initialize(1); delta_n_max.initializeHistory(); delta_t_max.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearUncoupled<spatial_dimension>::computeTraction( const Array<Real> &, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); delta_n_max.resize(); delta_t_max.resize(); damage_n.resize(); damage_t.resize(); /// define iterators - Array<Real>::vector_iterator traction_it = + auto traction_it = this->tractions(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator traction_end = + auto traction_end = this->tractions(el_type, ghost_type).end(spatial_dimension); - Array<Real>::vector_iterator opening_it = + auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); /// opening_prec is the opening of the previous step in the /// Newton-Raphson loop - Array<Real>::vector_iterator opening_prec_it = + auto opening_prec_it = this->opening_prec(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator contact_traction_it = + auto contact_traction_it = this->contact_tractions(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator contact_opening_it = + auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::const_vector_iterator normal_it = + auto normal_it = this->normal.begin(spatial_dimension); Array<Real>::scalar_iterator sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_n_max_it = delta_n_max(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_t_max_it = delta_t_max(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); Array<Real>::scalar_iterator damage_n_it = damage_n(el_type, ghost_type).begin(); Array<Real>::scalar_iterator damage_t_it = damage_t(el_type, ghost_type).begin(); - Array<Real>::vector_iterator insertion_stress_it = + auto insertion_stress_it = this->insertion_stress(el_type, ghost_type).begin(spatial_dimension); Array<bool>::scalar_iterator reduction_penalty_it = this->reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); if (!this->model->isDefaultSolverExplicit()) { this->delta_n_max(el_type, ghost_type) .copy(this->delta_n_max.previous(el_type, ghost_type)); this->delta_t_max(el_type, ghost_type) .copy(this->delta_t_max.previous(el_type, ghost_type)); } /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++opening_prec_it, ++contact_traction_it, ++contact_opening_it, ++normal_it, ++sigma_c_it, ++delta_n_max_it, ++delta_t_max_it, ++delta_c_it, ++damage_n_it, ++damage_t_it, ++insertion_stress_it, ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; Real delta_c2_R2 = *delta_c_it * (*delta_c_it) / R / R; /// compute normal and tangential opening vectors normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening = *normal_it; normal_opening *= normal_opening_norm; // std::cout<< "normal_opening_norm = " << normal_opening_norm // <<std::endl; Vector<Real> tangential_opening = *opening_it; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); /// compute effective opening displacement Real delta_n = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; Real delta_t = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm < 0.0; if (this->contact_after_breaking == false && Math::are_float_equal(*damage_n_it, 1.)) penetration = false; /** * If during the convergence loop a cohesive element continues to * jumps from penetration to opening, and convergence is not * reached, its penalty parameter will be reduced in the * recomputation of the same incremental step. Recompute is set * equal to true when convergence is not reached in the * solveStepCohesive function and the execution of the program * goes back to the main file where the variable load_reduction * is set equal to true. */ Real normal_opening_prec_norm = opening_prec_it->dot(*normal_it); // Vector<Real> normal_opening_prec = *normal_it; // normal_opening_prec *= normal_opening_prec_norm; if (!this->model->isDefaultSolverExplicit()) // && !this->recompute) if ((normal_opening_prec_norm * normal_opening_norm) < 0.0) *reduction_penalty_it = true; *opening_prec_it = *opening_it; if (penetration) { if (this->recompute && *reduction_penalty_it) { /// the penalty parameter is locally reduced current_penalty = this->penalty / 100.; } else current_penalty = this->penalty; /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= current_penalty; *contact_opening_it = normal_opening; /// don't consider penetration contribution for delta *opening_it = tangential_opening; normal_opening.clear(); } else { delta_n += normal_opening_norm * normal_opening_norm; delta_t += normal_opening_norm * normal_opening_norm * delta_c2_R2; contact_traction_it->clear(); contact_opening_it->clear(); } delta_n = std::sqrt(delta_n); delta_t = std::sqrt(delta_t); /// update maximum displacement and damage *delta_n_max_it = std::max(*delta_n_max_it, delta_n); *damage_n_it = std::min(*delta_n_max_it / *delta_c_it, Real(1.)); *delta_t_max_it = std::max(*delta_t_max_it, delta_t); *damage_t_it = std::min(*delta_t_max_it / *delta_c_it, Real(1.)); Vector<Real> normal_traction(spatial_dimension); Vector<Real> shear_traction(spatial_dimension); /// NORMAL TRACTIONS if (Math::are_float_equal(*damage_n_it, 1.)) normal_traction.clear(); else if (Math::are_float_equal(*damage_n_it, 0.)) { if (penetration) normal_traction.clear(); else normal_traction = *insertion_stress_it; } else { // the following formulation holds both in loading and in // unloading-reloading normal_traction = normal_opening; AKANTU_DEBUG_ASSERT(*delta_n_max_it != 0., "Division by zero, tolerance might be too low"); normal_traction *= *sigma_c_it / (*delta_n_max_it) * (1. - *damage_n_it); } /// SHEAR TRACTIONS if (Math::are_float_equal(*damage_t_it, 1.)) shear_traction.clear(); else if (Math::are_float_equal(*damage_t_it, 0.)) { shear_traction.clear(); } else { shear_traction = tangential_opening; AKANTU_DEBUG_ASSERT(*delta_t_max_it != 0., "Division by zero, tolerance might be too low"); shear_traction *= this->beta2_kappa; shear_traction *= *sigma_c_it / (*delta_t_max_it) * (1. - *damage_t_it); } *traction_it = normal_traction; *traction_it += shear_traction; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearUncoupled<spatial_dimension>::checkDeltaMax( GhostType ghost_type) { AKANTU_DEBUG_IN(); /** * This function set a predefined value to the parameter * delta_max_prev of the elements that have been inserted in the * last loading step for which convergence has not been * reached. This is done before reducing the loading and re-doing * the step. Otherwise, the updating of delta_max_prev would be * done with reference to the non-convergent solution. In this * function also other variables related to the contact and * friction behavior are correctly set. */ Mesh & mesh = this->fem_cohesive.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); /** * the variable "recompute" is set to true to activate the * procedure that reduces the penalty parameter for * compression. This procedure is available only during the phase of * load_reduction, that has to be set in the main file. The * penalty parameter will be reduced only for the elements having * reduction_penalty = true. */ this->recompute = true; for (; it != last_type; ++it) { Array<UInt> & elem_filter = this->element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; ElementType el_type = *it; // std::cout << "element type: " << el_type << std::endl; /// define iterators Array<Real>::scalar_iterator delta_n_max_it = delta_n_max(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_n_max_end = delta_n_max(el_type, ghost_type).end(); Array<Real>::scalar_iterator delta_n_max_prev_it = delta_n_max.previous(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_t_max_it = delta_t_max(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_t_max_prev_it = delta_t_max.previous(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); - Array<Real>::vector_iterator opening_prec_it = + auto opening_prec_it = this->opening_prec(el_type, ghost_type).begin(spatial_dimension); - Array<Real>::vector_iterator opening_prec_prev_it = + auto opening_prec_prev_it = this->opening_prec.previous(el_type, ghost_type) .begin(spatial_dimension); Int it = 0; /// loop on each quadrature point for (; delta_n_max_it != delta_n_max_end; ++delta_n_max_it, ++delta_t_max_it, ++delta_c_it, ++delta_n_max_prev_it, ++delta_t_max_prev_it, ++opening_prec_it, ++opening_prec_prev_it) { ++it; if (*delta_n_max_prev_it == 0) { /// elements inserted in the last incremental step, that did /// not converge *delta_n_max_it = *delta_c_it / 1000.; } else /// elements introduced in previous incremental steps, for /// which a correct value of delta_max_prev already exists *delta_n_max_it = *delta_n_max_prev_it; if (*delta_t_max_prev_it == 0) { *delta_t_max_it = *delta_c_it * this->kappa / this->beta / 1000.; } else *delta_t_max_it = *delta_t_max_prev_it; /// in case convergence is not reached, set opening_prec to the /// value referred to the previous incremental step *opening_prec_it = *opening_prec_prev_it; } } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinearUncoupled<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> &, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array<Real>::matrix_iterator tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); - Array<Real>::const_vector_iterator normal_it = + auto normal_it = this->normal.begin(spatial_dimension); - Array<Real>::vector_iterator opening_it = + auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); /// NB: delta_max_it points on delta_max_previous, i.e. the /// delta_max related to the solution of the previous incremental /// step Array<Real>::scalar_iterator delta_n_max_it = delta_n_max.previous(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_t_max_it = delta_t_max.previous(el_type, ghost_type).begin(); Array<Real>::scalar_iterator sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); Array<Real>::scalar_iterator delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); Array<Real>::scalar_iterator damage_n_it = damage_n(el_type, ghost_type).begin(); - Array<Real>::vector_iterator contact_opening_it = + auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); Array<bool>::scalar_iterator reduction_penalty_it = this->reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++sigma_c_it, ++delta_c_it, ++delta_n_max_it, ++delta_t_max_it, ++damage_n_it, ++contact_opening_it, ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; Real delta_c2_R2 = *delta_c_it * (*delta_c_it) / R / R; /** * During the update of the residual the interpenetrations are * stored in the array "contact_opening", therefore, in the case * of penetration, in the array "opening" there are only the * tangential components. */ *opening_it += *contact_opening_it; /// compute normal and tangential opening vectors normal_opening_norm = opening_it->dot(*normal_it); Vector<Real> normal_opening = *normal_it; normal_opening *= normal_opening_norm; Vector<Real> tangential_opening = *opening_it; tangential_opening -= normal_opening; tangential_opening_norm = tangential_opening.norm(); Real delta_n = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; Real delta_t = tangential_opening_norm * tangential_opening_norm * this->beta2_kappa2; penetration = normal_opening_norm < 0.0; if (this->contact_after_breaking == false && Math::are_float_equal(*damage_n_it, 1.)) penetration = false; Real derivative = 0; // derivative = d(t/delta)/ddelta Real T = 0; /// TANGENT STIFFNESS FOR NORMAL TRACTIONS Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); if (penetration) { if (this->recompute && *reduction_penalty_it) current_penalty = this->penalty / 100.; else current_penalty = this->penalty; /// stiffness in compression given by the penalty parameter *tangent_it = n_outer_n; *tangent_it *= current_penalty; *opening_it = tangential_opening; normal_opening.clear(); } else { delta_n += normal_opening_norm * normal_opening_norm; delta_n = std::sqrt(delta_n); delta_t += normal_opening_norm * normal_opening_norm * delta_c2_R2; /** * Delta has to be different from 0 to have finite values of * tangential stiffness. At the element insertion, delta = * 0. Therefore, a fictictious value is defined, for the * evaluation of the first value of K. */ if (delta_n < Math::getTolerance()) delta_n = *delta_c_it / 1000.; // loading if (delta_n >= *delta_n_max_it) { if (delta_n <= *delta_c_it) { derivative = -(*sigma_c_it) / (delta_n * delta_n); T = *sigma_c_it * (1 - delta_n / *delta_c_it); } else { derivative = 0.; T = 0.; } // unloading-reloading } else if (delta_n < *delta_n_max_it) { Real T_max = *sigma_c_it * (1 - *delta_n_max_it / *delta_c_it); derivative = 0.; T = T_max / *delta_n_max_it * delta_n; } /// computation of the derivative of the constitutive law (dT/ddelta) Matrix<Real> nn(n_outer_n); nn *= T / delta_n; Vector<Real> Delta_tilde(normal_opening); Delta_tilde *= (1. - this->beta2_kappa2); Vector<Real> mm(*opening_it); mm *= this->beta2_kappa2; Delta_tilde += mm; const Vector<Real> & Delta_hat(normal_opening); Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(Delta_hat, Delta_tilde); prov *= derivative / delta_n; prov += nn; Matrix<Real> prov_t = prov.transpose(); *tangent_it = prov_t; } derivative = 0.; T = 0.; /// TANGENT STIFFNESS FOR SHEAR TRACTIONS delta_t = std::sqrt(delta_t); /** * Delta has to be different from 0 to have finite values of * tangential stiffness. At the element insertion, delta = * 0. Therefore, a fictictious value is defined, for the * evaluation of the first value of K. */ if (delta_t < Math::getTolerance()) delta_t = *delta_c_it / 1000.; // loading if (delta_t >= *delta_t_max_it) { if (delta_t <= *delta_c_it) { derivative = -(*sigma_c_it) / (delta_t * delta_t); T = *sigma_c_it * (1 - delta_t / *delta_c_it); } else { derivative = 0.; T = 0.; } // unloading-reloading } else if (delta_t < *delta_t_max_it) { Real T_max = *sigma_c_it * (1 - *delta_t_max_it / *delta_c_it); derivative = 0.; T = T_max / *delta_t_max_it * delta_t; } /// computation of the derivative of the constitutive law (dT/ddelta) Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(); Matrix<Real> nn(n_outer_n); I -= nn; I *= T / delta_t; Vector<Real> Delta_tilde(normal_opening); Delta_tilde *= (delta_c2_R2 - this->beta2_kappa2); Vector<Real> mm(*opening_it); mm *= this->beta2_kappa2; Delta_tilde += mm; Vector<Real> Delta_hat(tangential_opening); Delta_hat *= this->beta2_kappa; Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(Delta_hat, Delta_tilde); prov *= derivative / delta_t; prov += I; Matrix<Real> prov_t = prov.transpose(); *tangent_it += prov_t; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear_uncoupled, MaterialCohesiveLinearUncoupled); } // akantu diff --git a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh index 24d4b45c6..f4c3c121d 100644 --- a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh +++ b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh @@ -1,190 +1,190 @@ /** * @file structural_element_bernoulli_beam_3.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation Tue Sep 19 2017 * * @brief Specific functions for bernoulli beam 3d * * @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_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH__ #define __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH__ #include "structural_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <> inline void StructuralMechanicsModel::assembleMass<_bernoulli_beam_3>() { AKANTU_DEBUG_IN(); #if 0 GhostType ghost_type = _not_ghost; ElementType type = _bernoulli_beam_3; MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); UInt nb_element = getFEEngine().getMesh().getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); UInt nb_fields_to_interpolate = getTangentStiffnessVoigtSize<_bernoulli_beam_3>(); UInt nt_n_field_size = nb_degree_of_freedom * nb_nodes_per_element; Array<Real> * n = new Array<Real>(nb_element * nb_quadrature_points, nb_fields_to_interpolate * nt_n_field_size, "N"); n->clear(); Array<Real> * rho_field = new Array<Real>(nb_element * nb_quadrature_points, "Rho"); rho_field->clear(); computeRho(*rho_field, type, _not_ghost); /* -------------------------------------------------------------------------- */ fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 0, 0, 0, true, ghost_type); // Ni ui -> u fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 1, 1, 1, true, ghost_type); // Mi vi -> v fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 2, 5, 1, true, ghost_type); // Li Theta_z_i -> v fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 1, 2, 2, true, ghost_type); // Mi wi -> w fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 2, 4, 2, false, ghost_type); // -Li Theta_y_i -> w fem.computeShapesMatrix(type, nb_degree_of_freedom, nb_nodes_per_element, n, 0, 3, 3, true, ghost_type); // Ni Theta_x_i->Theta_x /* -------------------------------------------------------------------------- */ fem.assembleFieldMatrix(*rho_field, nb_degree_of_freedom, *mass_matrix, n, rotation_matrix, type, ghost_type); delete n; delete rho_field; #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeRotationMatrix<_bernoulli_beam_3>( Array<Real> & rotations) { ElementType type = _bernoulli_beam_3; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); - Array<Real>::vector_iterator n_it = + auto n_it = mesh.getNormals(type).begin(spatial_dimension); Array<UInt>::iterator<Vector<UInt> > connec_it = mesh.getConnectivity(type).begin(2); - Array<Real>::vector_iterator nodes_it = + auto nodes_it = mesh.getNodes().begin(spatial_dimension); Matrix<Real> Pe(spatial_dimension, spatial_dimension); Matrix<Real> Pg(spatial_dimension, spatial_dimension); Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension); Vector<Real> x_n(spatial_dimension); // x vect n Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e = 0; e < nb_element; ++e, ++n_it, ++connec_it, ++R_it) { Vector<Real> & n = *n_it; Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x; x = nodes_it[connec(1)]; // X2 Vector<Real> y; y = nodes_it[connec(0)]; // X1 Real l = x.distance(y); x -= y; // X2 - X1 x_n.crossProduct(x, n); Pe.eye(); Pe(0, 0) *= l; Pe(1, 1) *= -l; Pg(0, 0) = x(0); Pg(0, 1) = x_n(0); Pg(0, 2) = n(0); Pg(1, 0) = x(1); Pg(1, 1) = x_n(1); Pg(1, 2) = n(1); Pg(2, 0) = x(2); Pg(2, 1) = x_n(2); Pg(2, 2) = n(2); inv_Pg.inverse(Pg); Pe *= inv_Pg; for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { R(i, j) = Pe(i, j); R(i + spatial_dimension, j + spatial_dimension) = Pe(i, j); } } } } /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_3>( Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(_bernoulli_beam_3); UInt tangent_size = 4; tangent_moduli.clear(); Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); for (UInt e = 0; e < nb_element; ++e) { UInt mat = element_material(_bernoulli_beam_3, _not_ghost)(e); Real E = materials[mat].E; Real A = materials[mat].A; Real Iz = materials[mat].Iz; Real Iy = materials[mat].Iy; Real GJ = materials[mat].GJ; for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0, 0) = E * A; D(1, 1) = E * Iz; D(2, 2) = E * Iy; D(3, 3) = GJ; } } } } // akantu #endif /* __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH__ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc index 0e33ccd73..172a8d000 100644 --- a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc +++ b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc @@ -1,361 +1,361 @@ /** * @file structural_mechanics_model_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Thu Oct 15 2015 * * @brief Implementation of inline functions of StructuralMechanicsModel * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free 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 "structural_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeTangentModuli( Array<Real> & /*tangent_moduli*/) { AKANTU_TO_IMPLEMENT(); } } // namespace akantu #include "structural_element_bernoulli_beam_2.hh" #include "structural_element_bernoulli_beam_3.hh" #include "structural_element_kirchhoff_shell.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); auto nb_element = getFEEngine().getMesh().getNbElement(type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); auto tangent_size = ElementClass<type>::getNbStressComponents(); auto tangent_moduli = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); computeTangentModuli<type>(*tangent_moduli); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = nb_degree_of_freedom * nb_nodes_per_element; auto bt_d_b = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); const auto & b = getFEEngine().getShapesDerivatives(type); Matrix<Real> BtD(bt_d_b_size, tangent_size); for (auto && tuple : zip(make_view(b, tangent_size, bt_d_b_size), make_view(*tangent_moduli, tangent_size, tangent_size), make_view(*bt_d_b, bt_d_b_size, bt_d_b_size))) { auto & B = std::get<0>(tuple); auto & D = std::get<1>(tuple); auto & BtDB = std::get<2>(tuple); BtD.mul<true, false>(B, D); BtDB.template mul<false, false>(BtD, B); } /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto int_bt_d_b = std::make_unique<Array<Real>>( nb_element, bt_d_b_size * bt_d_b_size, "int_B^t*D*B"); getFEEngine().integrate(*bt_d_b, *int_bt_d_b, bt_d_b_size * bt_d_b_size, type); getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *int_bt_d_b, type, _not_ghost, _symmetric); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeStressOnQuad() { AKANTU_DEBUG_IN(); Array<Real> & sigma = stress(type, _not_ghost); auto nb_element = mesh.getNbElement(type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); auto tangent_size = ElementClass<type>::getNbStressComponents(); auto tangent_moduli = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); computeTangentModuli<type>(*tangent_moduli); /// compute DB auto d_b_size = nb_degree_of_freedom * nb_nodes_per_element; auto d_b = std::make_unique<Array<Real>>(nb_element * nb_quadrature_points, d_b_size * tangent_size, "D*B"); const auto & b = getFEEngine().getShapesDerivatives(type); auto B = b.begin(tangent_size, d_b_size); auto D = tangent_moduli->begin(tangent_size, tangent_size); auto D_B = d_b->begin(tangent_size, d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++B, ++D, ++D_B) { D_B->template mul<false, false>(*D, *B); } } /// compute DBu D_B = d_b->begin(tangent_size, d_b_size); auto DBu = sigma.begin(tangent_size); Vector<Real> ul(d_b_size); Array<Real> u_el(0, d_b_size); FEEngine::extractNodalToElementField(mesh, *displacement_rotation, u_el, type); auto ug = u_el.begin(d_b_size); auto T = rotation_matrix(type).begin(d_b_size, d_b_size); for (UInt e = 0; e < nb_element; ++e, ++T, ++ug) { ul.mul<false>(*T, *ug); for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_B, ++DBu) { DBu->template mul<false>(*D_B, ul); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeForcesByLocalTractionArray( const Array<Real> & tractions) { AKANTU_DEBUG_IN(); #if 0 UInt nb_element = getFEEngine().getMesh().getNbElement(type); UInt nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(type); UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); // check dimension match AKANTU_DEBUG_ASSERT( Mesh::getSpatialDimension(type) == getFEEngine().getElementDimension(), "element type dimension does not match the dimension of boundaries : " << getFEEngine().getElementDimension() << " != " << Mesh::getSpatialDimension(type)); // check size of the vector AKANTU_DEBUG_ASSERT( tractions.size() == nb_quad * nb_element, "the size of the vector should be the total number of quadrature points"); // check number of components AKANTU_DEBUG_ASSERT(tractions.getNbComponent() == nb_degree_of_freedom, "the number of components should be the spatial " "dimension of the problem"); Array<Real> Nvoigt(nb_element * nb_quad, nb_degree_of_freedom * nb_degree_of_freedom * nb_nodes_per_element); transferNMatrixToSymVoigtNMatrix<type>(Nvoigt); Array<Real>::const_matrix_iterator N_it = Nvoigt.begin( nb_degree_of_freedom, nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); - Array<Real>::const_vector_iterator te_it = + auto te_it = tractions.begin(nb_degree_of_freedom); Array<Real> funct(nb_element * nb_quad, nb_degree_of_freedom * nb_nodes_per_element, 0.); Array<Real>::iterator<Vector<Real>> Fe_it = funct.begin(nb_degree_of_freedom * nb_nodes_per_element); Vector<Real> fe(nb_degree_of_freedom * nb_nodes_per_element); for (UInt e = 0; e < nb_element; ++e, ++T_it) { const Matrix<Real> & T = *T_it; for (UInt q = 0; q < nb_quad; ++q, ++N_it, ++te_it, ++Fe_it) { const Matrix<Real> & N = *N_it; const Vector<Real> & te = *te_it; Vector<Real> & Fe = *Fe_it; // compute N^t tl fe.mul<true>(N, te); // turn N^t tl back in the global referential Fe.mul<true>(T, fe); } } // allocate the vector that will contain the integrated values std::stringstream name; name << id << type << ":integral_boundary"; Array<Real> int_funct(nb_element, nb_degree_of_freedom * nb_nodes_per_element, name.str()); // do the integration getFEEngine().integrate(funct, int_funct, nb_degree_of_freedom * nb_nodes_per_element, type); // assemble the result into force vector getFEEngine().assembleArray(int_funct, *force_momentum, dof_synchronizer->getLocalDOFEquationNumbers(), nb_degree_of_freedom, type); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeForcesByGlobalTractionArray( const Array<Real> & traction_global) { AKANTU_DEBUG_IN(); #if 0 UInt nb_element = mesh.getNbElement(type); UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); UInt nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(type); std::stringstream name; name << id << ":structuralmechanics:imposed_linear_load"; Array<Real> traction_local(nb_element * nb_quad, nb_degree_of_freedom, name.str()); Array<Real>::const_matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_iterator<Vector<Real>> Te_it = traction_global.begin(nb_degree_of_freedom); Array<Real>::iterator<Vector<Real>> te_it = traction_local.begin(nb_degree_of_freedom); Matrix<Real> R(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e = 0; e < nb_element; ++e, ++T_it) { const Matrix<Real> & T = *T_it; for (UInt i = 0; i < nb_degree_of_freedom; ++i) for (UInt j = 0; j < nb_degree_of_freedom; ++j) R(i, j) = T(i, j); for (UInt q = 0; q < nb_quad; ++q, ++Te_it, ++te_it) { const Vector<Real> & Te = *Te_it; Vector<Real> & te = *te_it; // turn the traction in the local referential te.mul<false>(R, Te); } } computeForcesByLocalTractionArray<type>(traction_local); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @param myf pointer to a function that fills a vector/tensor with respect to * passed coordinates */ #if 0 template <ElementType type> inline void StructuralMechanicsModel::computeForcesFromFunction( BoundaryFunction myf, BoundaryFunctionType function_type) { /** function type is ** _bft_forces : linear load is given ** _bft_stress : stress function is given -> Not already done for this kind *of model */ std::stringstream name; name << id << ":structuralmechanics:imposed_linear_load"; Array<Real> lin_load(0, nb_degree_of_freedom, name.str()); name.clear(); UInt offset = nb_degree_of_freedom; // prepare the loop over element types UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); UInt nb_element = getFEEngine().getMesh().getNbElement(type); name.clear(); name << id << ":structuralmechanics:quad_coords"; Array<Real> quad_coords(nb_element * nb_quad, spatial_dimension, "quad_coords"); getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>(getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension); getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>( getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension, _not_ghost, empty_filter, true, 0, 1, 1); if (spatial_dimension == 3) getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>( getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension, _not_ghost, empty_filter, true, 0, 2, 2); lin_load.resize(nb_element * nb_quad); Real * imposed_val = lin_load.storage(); /// sigma/load on each quadrature points Real * qcoord = quad_coords.storage(); for (UInt el = 0; el < nb_element; ++el) { for (UInt q = 0; q < nb_quad; ++q) { myf(qcoord, imposed_val, NULL, 0); imposed_val += offset; qcoord += spatial_dimension; } } switch (function_type) { case _bft_traction_local: computeForcesByLocalTractionArray<type>(lin_load); break; case _bft_traction: computeForcesByGlobalTractionArray<type>(lin_load); break; default: break; } } #endif } // namespace akantu #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ */ diff --git a/test/test_model/test_model_solver/test_model_solver_my_model.hh b/test/test_model/test_model_solver/test_model_solver_my_model.hh index 769a14e5f..9512d53d9 100644 --- a/test/test_model/test_model_solver/test_model_solver_my_model.hh +++ b/test/test_model/test_model_solver/test_model_solver_my_model.hh @@ -1,468 +1,468 @@ /** * @file test_dof_manager_default.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Feb 24 12:28:44 2016 * * @brief Test default dof manager * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "data_accessor.hh" #include "dof_manager_default.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "model_solver.hh" #include "sparse_matrix.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ namespace akantu { #ifndef __AKANTU_TEST_MODEL_SOLVER_MY_MODEL_HH__ #define __AKANTU_TEST_MODEL_SOLVER_MY_MODEL_HH__ /** * =\o-----o-----o-> F * | | * |---- L ----| */ class MyModel : public ModelSolver, public DataAccessor<Element> { public: MyModel(Real F, Mesh & mesh, bool lumped) : ModelSolver(mesh, ModelType::_model, "model_solver", 0), nb_dofs(mesh.getNbNodes()), nb_elements(mesh.getNbElement()), E(1.), A(1.), rho(1.), lumped(lumped), mesh(mesh), displacement(nb_dofs, 1, "disp"), velocity(nb_dofs, 1, "velo"), acceleration(nb_dofs, 1, "accel"), blocked(nb_dofs, 1, "blocked"), forces(nb_dofs, 1, "force_ext"), internal_forces(nb_dofs, 1, "force_int"), stresses(nb_elements, 1, "stress"), strains(nb_elements, 1, "strain"), initial_lengths(nb_elements, 1, "L0") { this->initDOFManager(); this->getDOFManager().registerDOFs("disp", displacement, _dst_nodal); this->getDOFManager().registerDOFsDerivative("disp", 1, velocity); this->getDOFManager().registerDOFsDerivative("disp", 2, acceleration); this->getDOFManager().registerBlockedDOFs("disp", blocked); displacement.set(0.); velocity.set(0.); acceleration.set(0.); forces.set(0.); blocked.set(false); UInt global_nb_nodes = mesh.getNbGlobalNodes(); for (auto && n : arange(nb_dofs)) { auto global_id = mesh.getNodeGlobalId(n); if (global_id == (global_nb_nodes - 1)) forces(n, _x) = F; if (global_id == 0) blocked(n, _x) = true; } auto cit = this->mesh.getConnectivity(_segment_2).begin(2); auto cend = this->mesh.getConnectivity(_segment_2).end(2); auto L_it = this->initial_lengths.begin(); for (; cit != cend; ++cit, ++L_it) { const Vector<UInt> & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); *L_it = std::abs(p2 - p1); } this->registerDataAccessor(*this); this->registerSynchronizer( const_cast<ElementSynchronizer &>(this->mesh.getElementSynchronizer()), _gst_user_1); } void assembleLumpedMass() { Array<Real> & M = this->getDOFManager().getLumpedMatrix("M"); M.clear(); this->assembleLumpedMass(_not_ghost); if (this->mesh.getNbElement(_segment_2, _ghost) > 0) this->assembleLumpedMass(_ghost); is_lumped_mass_assembled = true; } void assembleLumpedMass(const GhostType & ghost_type) { Array<Real> & M = this->getDOFManager().getLumpedMatrix("M"); Array<Real> m_all_el(this->mesh.getNbElement(_segment_2, ghost_type), 2); - Array<Real>::vector_iterator m_it = m_all_el.begin(2); + auto m_it = m_all_el.begin(2); auto cit = this->mesh.getConnectivity(_segment_2, ghost_type).begin(2); auto cend = this->mesh.getConnectivity(_segment_2, ghost_type).end(2); for (; cit != cend; ++cit, ++m_it) { const Vector<UInt> & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); Real L = std::abs(p2 - p1); Real M_n = rho * A * L / 2; (*m_it)(0) = (*m_it)(1) = M_n; } this->getDOFManager().assembleElementalArrayLocalArray( m_all_el, M, _segment_2, ghost_type); } void assembleMass() { SparseMatrix & M = this->getDOFManager().getMatrix("M"); M.clear(); Array<Real> m_all_el(this->nb_elements, 4); Array<Real>::matrix_iterator m_it = m_all_el.begin(2, 2); auto cit = this->mesh.getConnectivity(_segment_2).begin(2); auto cend = this->mesh.getConnectivity(_segment_2).end(2); Matrix<Real> m(2, 2); m(0, 0) = m(1, 1) = 2; m(0, 1) = m(1, 0) = 1; // under integrated // m(0, 0) = m(1, 1) = 3./2.; // m(0, 1) = m(1, 0) = 3./2.; // lumping the mass matrix // m(0, 0) += m(0, 1); // m(1, 1) += m(1, 0); // m(0, 1) = m(1, 0) = 0; for (; cit != cend; ++cit, ++m_it) { const Vector<UInt> & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); Real L = std::abs(p2 - p1); Matrix<Real> & m_el = *m_it; m_el = m; m_el *= rho * A * L / 6.; } this->getDOFManager().assembleElementalMatricesToMatrix( "M", "disp", m_all_el, _segment_2); is_mass_assembled = true; } MatrixType getMatrixType(const ID &) { return _symmetric; } void assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { if (not is_stiffness_assembled) this->assembleStiffness(); } else if (matrix_id == "M") { if (not is_mass_assembled) this->assembleMass(); } else if (matrix_id == "C") { // pass, no damping matrix } else { AKANTU_EXCEPTION("This solver does not know what to do with a matrix " << matrix_id); } } void assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { if (not is_lumped_mass_assembled) this->assembleLumpedMass(); } else { AKANTU_EXCEPTION("This solver does not know what to do with a matrix " << matrix_id); } } void assembleStiffness() { SparseMatrix & K = this->getDOFManager().getMatrix("K"); K.clear(); Matrix<Real> k(2, 2); k(0, 0) = k(1, 1) = 1; k(0, 1) = k(1, 0) = -1; Array<Real> k_all_el(this->nb_elements, 4); auto k_it = k_all_el.begin(2, 2); auto cit = this->mesh.getConnectivity(_segment_2).begin(2); auto cend = this->mesh.getConnectivity(_segment_2).end(2); for (; cit != cend; ++cit, ++k_it) { const auto & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real p1 = this->mesh.getNodes()(n1, _x); Real p2 = this->mesh.getNodes()(n2, _x); Real L = std::abs(p2 - p1); auto & k_el = *k_it; k_el = k; k_el *= E * A / L; } this->getDOFManager().assembleElementalMatricesToMatrix( "K", "disp", k_all_el, _segment_2); is_stiffness_assembled = true; } void assembleResidual() { this->getDOFManager().assembleToResidual("disp", forces); internal_forces.clear(); this->assembleResidual(_not_ghost); this->synchronize(_gst_user_1); this->getDOFManager().assembleToResidual("disp", internal_forces, -1.); // auto & comm = Communicator::getStaticCommunicator(); // const auto & dof_manager_default = // dynamic_cast<DOFManagerDefault &>(this->getDOFManager()); // const auto & residual = dof_manager_default.getResidual(); // int prank = comm.whoAmI(); // int psize = comm.getNbProc(); // for (int p = 0; p < psize; ++p) { // if (prank == p) { // UInt local_dof = 0; // for (auto res : residual) { // UInt global_dof = // dof_manager_default.localToGlobalEquationNumber(local_dof); // std::cout << local_dof << " [" << global_dof << " - " // << dof_manager_default.getDOFType(local_dof) << "]: " << // res // << std::endl; // ++local_dof; // } // std::cout << std::flush; // } // comm.barrier(); // } // comm.barrier(); // if(prank == 0) std::cout << "===========================" << std::endl; } void assembleResidual(const GhostType & ghost_type) { Array<Real> forces_internal_el( this->mesh.getNbElement(_segment_2, ghost_type), 2); auto cit = this->mesh.getConnectivity(_segment_2, ghost_type).begin(2); auto cend = this->mesh.getConnectivity(_segment_2, ghost_type).end(2); auto f_it = forces_internal_el.begin(2); auto strain_it = this->strains.begin(); auto stress_it = this->stresses.begin(); auto L_it = this->initial_lengths.begin(); for (; cit != cend; ++cit, ++f_it, ++strain_it, ++stress_it, ++L_it) { const auto & conn = *cit; UInt n1 = conn(0); UInt n2 = conn(1); Real u1 = this->displacement(n1, _x); Real u2 = this->displacement(n2, _x); *strain_it = (u2 - u1) / *L_it; *stress_it = E * *strain_it; Real f_n = A * *stress_it; Vector<Real> & f = *f_it; f(0) = -f_n; f(1) = f_n; } this->getDOFManager().assembleElementalArrayLocalArray( forces_internal_el, internal_forces, _segment_2, ghost_type); } Real getPotentialEnergy() { Real res = 0; if (!lumped) { res = this->mulVectMatVect(this->displacement, this->getDOFManager().getMatrix("K"), this->displacement); } else { auto strain_it = this->strains.begin(); auto stress_it = this->stresses.begin(); auto strain_end = this->strains.end(); auto L_it = this->initial_lengths.begin(); for (; strain_it != strain_end; ++strain_it, ++stress_it, ++L_it) { res += *strain_it * *stress_it * A * *L_it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); } return res / 2.; } Real getKineticEnergy() { Real res = 0; if (!lumped) { res = this->mulVectMatVect( this->velocity, this->getDOFManager().getMatrix("M"), this->velocity); } else { auto & m = this->getDOFManager().getLumpedMatrix("M"); auto it = velocity.begin(); auto end = velocity.end(); auto m_it = m.begin(); for (UInt node = 0; it != end; ++it, ++m_it, ++node) { if (mesh.isLocalOrMasterNode(node)) res += *m_it * *it * *it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); } return res / 2.; } Real getExternalWorkIncrement() { Real res = 0; auto it = velocity.begin(); auto end = velocity.end(); auto if_it = internal_forces.begin(); auto ef_it = forces.begin(); auto b_it = blocked.begin(); for (UInt node = 0; it != end; ++it, ++if_it, ++ef_it, ++b_it, ++node) { if (mesh.isLocalOrMasterNode(node)) res += (*b_it ? -*if_it : *ef_it) * *it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); return res * this->getTimeStep(); } Real mulVectMatVect(const Array<Real> & x, const SparseMatrix & A, const Array<Real> & y) { Array<Real> Ay(this->nb_dofs, 1, 0.); A.matVecMul(y, Ay); Real res = 0.; Array<Real>::const_scalar_iterator it = Ay.begin(); Array<Real>::const_scalar_iterator end = Ay.end(); Array<Real>::const_scalar_iterator x_it = x.begin(); for (UInt node = 0; it != end; ++it, ++x_it, ++node) { if (mesh.isLocalOrMasterNode(node)) res += *x_it * *it; } mesh.getCommunicator().allReduce(res, SynchronizerOperation::_sum); return res; } void predictor() {} void corrector() {} /* ------------------------------------------------------------------------ */ UInt getNbData(const Array<Element> & elements, const SynchronizationTag &) const { return elements.size() * sizeof(Real); } void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_user_1) { for (const auto & el : elements) { buffer << this->stresses(el.element); } } } void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_user_1) { auto cit = this->mesh.getConnectivity(_segment_2, _ghost).begin(2); for (const auto & el : elements) { Real stress; buffer >> stress; Real f = A * stress; Vector<UInt> conn = cit[el.element]; this->internal_forces(conn(0), _x) += -f; this->internal_forces(conn(1), _x) += f; } } } private: UInt nb_dofs; UInt nb_elements; Real E, A, rho; bool lumped; bool is_stiffness_assembled{false}; bool is_mass_assembled{false}; bool is_lumped_mass_assembled{false}; public: Mesh & mesh; Array<Real> displacement; Array<Real> velocity; Array<Real> acceleration; Array<bool> blocked; Array<Real> forces; Array<Real> internal_forces; Array<Real> stresses; Array<Real> strains; Array<Real> initial_lengths; }; #endif /* __AKANTU_TEST_MODEL_SOLVER_MY_MODEL_HH__ */ } // akantu diff --git a/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc index a266d813a..64de9a4ba 100644 --- a/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc +++ b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc @@ -1,191 +1,191 @@ /** * @file test_build_neighborhood_parallel.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief test in parallel for the class NonLocalNeighborhood * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_iohelper_paraview.hh" #include "non_local_neighborhood_base.hh" #include "solid_mechanics_model.hh" #include "test_material.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { akantu::initialize("material_parallel_test.dat", argc, argv); const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); // some configuration variables const UInt spatial_dimension = 2; // mesh creation and read Mesh mesh(spatial_dimension); if (prank == 0) { mesh.read("parallel_test.msh"); } mesh.distribute(); /// model creation SolidMechanicsModel model(mesh); /// dump the ghost elements before the non-local part is intialized DumperParaview dumper_ghost("ghost_elements"); dumper_ghost.registerMesh(mesh, spatial_dimension, _ghost); if (psize > 1) { dumper_ghost.dump(); } /// creation of material selector auto && mat_selector = std::make_shared<MeshDataMaterialSelector<std::string>>("physical_names", model); model.setMaterialSelector(mat_selector); /// dump material index in paraview model.addDumpField("partitions"); model.dump(); /// model initialization changed to use our material model.initFull(); /// dump the ghost elements after ghosts for non-local have been added if (psize > 1) dumper_ghost.dump(); model.addDumpField("grad_u"); model.addDumpField("grad_u non local"); model.addDumpField("material_index"); /// apply constant strain field everywhere in the plate Matrix<Real> applied_strain(spatial_dimension, spatial_dimension); applied_strain.clear(); for (UInt i = 0; i < spatial_dimension; ++i) applied_strain(i, i) = 2.; ElementType element_type = _triangle_3; GhostType ghost_type = _not_ghost; /// apply constant grad_u field in all elements for (UInt m = 0; m < model.getNbMaterials(); ++m) { auto & mat = model.getMaterial(m); auto & grad_u = const_cast<Array<Real> &>( mat.getInternal<Real>("grad_u")(element_type, ghost_type)); auto grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); auto grad_u_end = grad_u.end(spatial_dimension, spatial_dimension); for (; grad_u_it != grad_u_end; ++grad_u_it) (*grad_u_it) = -1. * applied_strain; } /// double the strain in the center: find the closed gauss point to the center /// compute the quadrature points ElementTypeMapReal quad_coords("quad_coords"); quad_coords.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _with_nb_element = true); model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); Vector<Real> center(spatial_dimension, 0.); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_regular); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_regular); Real min_distance = 2; IntegrationPoint q_min; for (; it != last_type; ++it) { ElementType type = *it; UInt nb_elements = mesh.getNbElement(type, _not_ghost); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(type); Array<Real> & coords = quad_coords(type, _not_ghost); - Array<Real>::const_vector_iterator coord_it = + auto coord_it = coords.begin(spatial_dimension); for (UInt e = 0; e < nb_elements; ++e) { for (UInt q = 0; q < nb_quads; ++q, ++coord_it) { Real dist = center.distance(*coord_it); if (dist < min_distance) { min_distance = dist; q_min.element = e; q_min.num_point = q; q_min.global_num = nb_elements * nb_quads + q; q_min.type = type; } } } } Real global_min = min_distance; comm.allReduce(global_min, SynchronizerOperation::_min); if (Math::are_float_equal(global_min, min_distance)) { UInt mat_index = model.getMaterialByElement(q_min.type, _not_ghost) .begin()[q_min.element]; Material & mat = model.getMaterial(mat_index); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(q_min.type); UInt local_el_index = model.getMaterialLocalNumbering(q_min.type, _not_ghost) .begin()[q_min.element]; UInt local_num = (local_el_index * nb_quads) + q_min.num_point; Array<Real> & grad_u = const_cast<Array<Real> &>( mat.getInternal<Real>("grad_u")(q_min.type, _not_ghost)); Array<Real>::iterator<Matrix<Real>> grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); grad_u_it += local_num; Matrix<Real> & g_u = *grad_u_it; g_u += applied_strain; } /// compute the non-local strains model.assembleInternalForces(); model.dump(); /// damage the element with higher grad_u completely, so that it is /// not taken into account for the averaging if (Math::are_float_equal(global_min, min_distance)) { UInt mat_index = model.getMaterialByElement(q_min.type, _not_ghost) .begin()[q_min.element]; Material & mat = model.getMaterial(mat_index); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(q_min.type); UInt local_el_index = model.getMaterialLocalNumbering(q_min.type, _not_ghost) .begin()[q_min.element]; UInt local_num = (local_el_index * nb_quads) + q_min.num_point; Array<Real> & damage = const_cast<Array<Real> &>( mat.getInternal<Real>("damage")(q_min.type, _not_ghost)); Real * dam_ptr = damage.storage(); dam_ptr += local_num; *dam_ptr = 0.9; } /// compute the non-local strains model.assembleInternalForces(); model.dump(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_non_local_toolbox/test_pair_computation.cc b/test/test_model/test_non_local_toolbox/test_pair_computation.cc index 486954a9f..d70a01ea5 100644 --- a/test/test_model/test_non_local_toolbox/test_pair_computation.cc +++ b/test/test_model/test_non_local_toolbox/test_pair_computation.cc @@ -1,224 +1,224 @@ /** * @file test_pair_computation.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Wed Nov 25 2015 * * @brief test the weight computation with and without grid * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "dumper_paraview.hh" #include "non_local_manager.hh" #include "non_local_neighborhood.hh" #include "solid_mechanics_model.hh" #include "test_material_damage.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; typedef std::vector<std::pair<IntegrationPoint, IntegrationPoint>> PairList; /* -------------------------------------------------------------------------- */ void computePairs(SolidMechanicsModel & model, PairList * pair_list); int main(int argc, char * argv[]) { akantu::initialize("material_remove_damage.dat", argc, argv); // some configuration variables const UInt spatial_dimension = 2; const auto & comm = Communicator::getStaticCommunicator(); Int prank = comm.whoAmI(); // mesh creation and read Mesh mesh(spatial_dimension); if (prank == 0) { mesh.read("pair_test.msh"); } mesh.distribute(); /// model creation SolidMechanicsModel model(mesh); /// creation of material selector auto && mat_selector = std::make_shared<MeshDataMaterialSelector<std::string>>("physical_names", model); model.setMaterialSelector(mat_selector); /// model initialization changed to use our material model.initFull(); /// dump material index in paraview model.addDumpField("material_index"); model.dump(); /// compute the pairs by looping over all the quadrature points PairList pair_list[2]; computePairs(model, pair_list); const PairList * pairs_mat_1 = model.getNonLocalManager().getNeighborhood("mat_1").getPairLists(); const PairList * pairs_mat_2 = model.getNonLocalManager().getNeighborhood("mat_2").getPairLists(); /// compare the number of pairs UInt nb_not_ghost_pairs_grid = pairs_mat_1[0].size() + pairs_mat_2[0].size(); UInt nb_ghost_pairs_grid = pairs_mat_1[1].size() + pairs_mat_2[1].size(); UInt nb_not_ghost_pairs_no_grid = pair_list[0].size(); UInt nb_ghost_pairs_no_grid = pair_list[1].size(); if ((nb_not_ghost_pairs_grid != nb_not_ghost_pairs_no_grid) || (nb_ghost_pairs_grid != nb_ghost_pairs_no_grid)) { std::cout << "The number of pairs is not correct: TEST FAILED!!!" << std::endl; finalize(); return EXIT_FAILURE; } for (UInt i = 0; i < pairs_mat_1[0].size(); ++i) { PairList::const_iterator it = std::find( pair_list[0].begin(), pair_list[0].end(), (pairs_mat_1[0])[i]); if (it == pair_list[0].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } for (UInt i = 0; i < pairs_mat_2[0].size(); ++i) { PairList::const_iterator it = std::find( pair_list[0].begin(), pair_list[0].end(), (pairs_mat_2[0])[i]); if (it == pair_list[0].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } for (UInt i = 0; i < pairs_mat_1[1].size(); ++i) { PairList::const_iterator it = std::find( pair_list[1].begin(), pair_list[1].end(), (pairs_mat_1[1])[i]); if (it == pair_list[1].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } for (UInt i = 0; i < pairs_mat_2[1].size(); ++i) { PairList::const_iterator it = std::find( pair_list[1].begin(), pair_list[1].end(), (pairs_mat_2[1])[i]); if (it == pair_list[1].end()) { std::cout << "The pairs are not correct" << std::endl; finalize(); return EXIT_FAILURE; } } finalize(); return 0; } /* -------------------------------------------------------------------------- */ void computePairs(SolidMechanicsModel & model, PairList * pair_list) { ElementKind kind = _ek_regular; Mesh & mesh = model.getMesh(); UInt spatial_dimension = model.getSpatialDimension(); /// compute the quadrature points ElementTypeMapReal quad_coords("quad_coords"); quad_coords.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _with_nb_element = true); model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); /// loop in a n^2 way over all the quads to generate the pairs Real neighborhood_radius = 0.5; Mesh::type_iterator it_1 = mesh.firstType(spatial_dimension, _not_ghost, kind); Mesh::type_iterator last_type_1 = mesh.lastType(spatial_dimension, _not_ghost, kind); IntegrationPoint q1; IntegrationPoint q2; GhostType ghost_type_1 = _not_ghost; q1.ghost_type = ghost_type_1; Vector<Real> q1_coords(spatial_dimension); Vector<Real> q2_coords(spatial_dimension); for (; it_1 != last_type_1; ++it_1) { ElementType type_1 = *it_1; q1.type = type_1; UInt nb_elements_1 = mesh.getNbElement(type_1, ghost_type_1); UInt nb_quads_1 = model.getFEEngine().getNbIntegrationPoints(type_1); Array<Real> & quad_coords_1 = quad_coords(q1.type, q1.ghost_type); - Array<Real>::const_vector_iterator coord_it_1 = + auto coord_it_1 = quad_coords_1.begin(spatial_dimension); for (UInt e_1 = 0; e_1 < nb_elements_1; ++e_1) { q1.element = e_1; UInt mat_index_1 = model.getMaterialByElement(q1.type, q1.ghost_type) .begin()[q1.element]; for (UInt q_1 = 0; q_1 < nb_quads_1; ++q_1) { q1.global_num = nb_quads_1 * e_1 + q_1; q1.num_point = q_1; q1_coords = coord_it_1[q1.global_num]; /// loop over all other quads and create pairs for this given quad for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type_2 = *gt; q2.ghost_type = ghost_type_2; Mesh::type_iterator it_2 = mesh.firstType(spatial_dimension, ghost_type_2, kind); Mesh::type_iterator last_type_2 = mesh.lastType(spatial_dimension, ghost_type_2, kind); for (; it_2 != last_type_2; ++it_2) { ElementType type_2 = *it_2; q2.type = type_2; UInt nb_elements_2 = mesh.getNbElement(type_2, ghost_type_2); UInt nb_quads_2 = model.getFEEngine().getNbIntegrationPoints(type_2); Array<Real> & quad_coords_2 = quad_coords(q2.type, q2.ghost_type); - Array<Real>::const_vector_iterator coord_it_2 = + auto coord_it_2 = quad_coords_2.begin(spatial_dimension); for (UInt e_2 = 0; e_2 < nb_elements_2; ++e_2) { q2.element = e_2; UInt mat_index_2 = model.getMaterialByElement(q2.type, q2.ghost_type) .begin()[q2.element]; for (UInt q_2 = 0; q_2 < nb_quads_2; ++q_2) { q2.global_num = nb_quads_2 * e_2 + q_2; q2.num_point = q_2; q2_coords = coord_it_2[q2.global_num]; Real distance = q1_coords.distance(q2_coords); if (mat_index_1 != mat_index_2) continue; else if (distance <= neighborhood_radius + Math::getTolerance() && (q2.ghost_type == _ghost || (q2.ghost_type == _not_ghost && q1.global_num <= q2.global_num))) { // storing only half lists pair_list[q2.ghost_type].push_back(std::make_pair(q1, q2)); } } } } } } } } } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo index ad9490148..8f460dd2f 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo @@ -1,33 +1,33 @@ h = 0.5; -Point(1) = { 1, 1, -.5, h}; -Point(2) = {-1, 1, -.5, h}; -Point(3) = {-1,-1, -.5, h}; -Point(4) = { 1,-1, -.5, h}; +Point(1) = { 1, 1, -1, h}; +Point(2) = {-1, 1, -1, h}; +Point(3) = {-1,-1, -1, h}; +Point(4) = { 1,-1, -1, h}; -Point(5) = {-1, 0, -.5, h}; -Point(6) = { 1, 0, -.5, h}; +Point(5) = {-1, 0, -1, h}; +Point(6) = { 1, 0, -1, h}; Line(1) = {1, 2}; Line(2) = {2, 5}; Line(3) = {5, 6}; Line(4) = {6, 1}; Line(5) = {5, 3}; Line(6) = {3, 4}; Line(7) = {4, 6}; Line Loop(1) = {1, 2, 3, 4}; Line Loop(2) = {-3, 5, 6, 7}; Plane Surface(1) = {1}; Plane Surface(2) = {2}; -Extrude {0, 0, 1} { +Extrude {0, 0, 2} { Surface{1}; Surface{2}; } Physical Surface("fixed") = {46}; Physical Surface("insertion") = {24}; Physical Surface("loading") = {16}; Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42}; Physical Volume("body") = {1, 2}; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc index 5817e0c22..f6e248d39 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_buildfragments/test_cohesive_parallel_buildfragments.cc @@ -1,432 +1,432 @@ /** * @file test_cohesive_parallel_buildfragments.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Test to build fragments in parallel * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include <limits> #include <fstream> #include <iostream> #include <algorithm> #include <functional> /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "material_cohesive.hh" #include "fragment_manager.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; void verticalInsertionLimit(SolidMechanicsModelCohesive &); void displaceElements(SolidMechanicsModelCohesive &, const Real, const Real); bool isInertiaEqual(const Vector<Real> &, const Vector<Real> &); void rotateArray(Array<Real> & array, Real angle); UInt getNbBigFragments(FragmentManager &, UInt); const UInt spatial_dimension = 3; const UInt total_nb_fragment = 4; const Real rotation_angle = M_PI / 4.; const Real global_tolerance = 1.e-9; int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); Math::setTolerance(global_tolerance); Mesh mesh(spatial_dimension); const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("mesh.msh"); /// partition the mesh MeshUtils::purifyMesh(mesh); partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); delete partition; /// model initialization model.initFull(SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); mesh.computeBoundingBox(); Real L = mesh.getUpperBounds()(0) - mesh.getLowerBounds()(0); Real h = mesh.getUpperBounds()(1) - mesh.getLowerBounds()(1); Real rho = model.getMaterial("bulk").getParam<Real>("rho"); Real theoretical_mass = L * h * h * rho; Real frag_theo_mass = theoretical_mass / total_nb_fragment; UInt nb_element = mesh.getNbElement(spatial_dimension, _not_ghost, _ek_regular); comm.allReduce(&nb_element, 1, _so_sum); UInt nb_element_per_fragment = nb_element / total_nb_fragment; FragmentManager fragment_manager(model); fragment_manager.computeAllData(); getNbBigFragments(fragment_manager, nb_element_per_fragment + 1); model.setBaseName("extrinsic"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity"); model.addDumpField("stress"); model.addDumpField("partitions"); model.addDumpField("fragments"); model.addDumpField("fragments mass"); model.addDumpField("moments of inertia"); model.addDumpField("elements per fragment"); model.dump(); model.setBaseNameToDumper("cohesive elements", "cohesive_elements_test"); model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.addDumpFieldToDumper("cohesive elements", "damage"); model.dump("cohesive elements"); /// set check facets verticalInsertionLimit(model); model.assembleMassLumped(); model.synchronizeBoundaries(); /// impose initial displacement Array<Real> & displacement = model.getDisplacement(); Array<Real> & velocity = model.getVelocity(); const Array<Real> & position = mesh.getNodes(); UInt nb_nodes = mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { displacement(n, 0) = position(n, 0) * 0.1; velocity(n, 0) = position(n, 0); } rotateArray(mesh.getNodes(), rotation_angle); // rotateArray(displacement, rotation_angle); // rotateArray(velocity, rotation_angle); model.updateResidual(); model.checkCohesiveStress(); model.dump(); model.dump("cohesive elements"); const Array<Real> & fragment_mass = fragment_manager.getMass(); const Array<Real> & fragment_center = fragment_manager.getCenterOfMass(); Real el_size = L / total_nb_fragment; Real lim = -L/2 + el_size * 0.99; /// define theoretical inertia moments Vector<Real> small_frag_inertia(spatial_dimension); small_frag_inertia(0) = frag_theo_mass * (h*h + h*h) / 12.; small_frag_inertia(1) = frag_theo_mass * (el_size*el_size + h*h) / 12.; small_frag_inertia(2) = frag_theo_mass * (el_size*el_size + h*h) / 12.; std::sort(small_frag_inertia.storage(), small_frag_inertia.storage() + spatial_dimension, std::greater<Real>()); const Array<Real> & inertia_moments = fragment_manager.getMomentsOfInertia(); Array<Real>::const_iterator< Vector<Real> > inertia_moments_begin = inertia_moments.begin(spatial_dimension); /// displace one fragment each time for (UInt frag = 1; frag <= total_nb_fragment; ++frag) { if (prank == 0) std::cout << "Generating fragment: " << frag << std::endl; fragment_manager.computeAllData(); /// check number of big fragments UInt nb_big_fragment = getNbBigFragments(fragment_manager, nb_element_per_fragment + 1); model.dump(); model.dump("cohesive elements"); if (frag < total_nb_fragment) { if (nb_big_fragment != 1) { AKANTU_ERROR("The number of big fragments is wrong: " << nb_big_fragment); return EXIT_FAILURE; } } else { if (nb_big_fragment != 0) { AKANTU_ERROR("The number of big fragments is wrong: " << nb_big_fragment); return EXIT_FAILURE; } } /// check number of fragments UInt nb_fragment_num = fragment_manager.getNbFragment(); if (nb_fragment_num != frag) { AKANTU_ERROR("The number of fragments is wrong! Numerical: " << nb_fragment_num << " Theoretical: " << frag); return EXIT_FAILURE; } /// check mass computation if (frag < total_nb_fragment) { Real total_mass = 0.; UInt small_fragments = 0; for (UInt f = 0; f < nb_fragment_num; ++f) { const Vector<Real> & current_inertia = inertia_moments_begin[f]; if (Math::are_float_equal(fragment_mass(f, 0), frag_theo_mass)) { /// check center of mass if (fragment_center(f, 0) > (L * frag / total_nb_fragment - L / 2)) { AKANTU_ERROR("Fragment center is wrong!"); return EXIT_FAILURE; } /// check moment of inertia if (!isInertiaEqual(current_inertia, small_frag_inertia)) { AKANTU_ERROR("Inertia moments are wrong"); return EXIT_FAILURE; } ++small_fragments; total_mass += frag_theo_mass; } else { /// check the moment of inertia for the biggest fragment Real big_frag_mass = frag_theo_mass * (total_nb_fragment - frag + 1); Real big_frag_size = el_size * (total_nb_fragment - frag + 1); Vector<Real> big_frag_inertia(spatial_dimension); big_frag_inertia(0) = big_frag_mass * (h*h + h*h) / 12.; big_frag_inertia(1) = big_frag_mass * (big_frag_size*big_frag_size + h*h) / 12.; big_frag_inertia(2) = big_frag_mass * (big_frag_size*big_frag_size + h*h) / 12.; std::sort(big_frag_inertia.storage(), big_frag_inertia.storage() + spatial_dimension, std::greater<Real>()); if (!isInertiaEqual(current_inertia, big_frag_inertia)) { AKANTU_ERROR("Inertia moments are wrong"); return EXIT_FAILURE; } } } if (small_fragments != nb_fragment_num - 1) { AKANTU_ERROR("The number of small fragments is wrong!"); return EXIT_FAILURE; } if (!Math::are_float_equal(total_mass, small_fragments * frag_theo_mass)) { AKANTU_ERROR("The mass of small fragments is wrong!"); return EXIT_FAILURE; } } /// displace fragments rotateArray(mesh.getNodes(), -rotation_angle); // rotateArray(displacement, -rotation_angle); displaceElements(model, lim, el_size * 2); rotateArray(mesh.getNodes(), rotation_angle); // rotateArray(displacement, rotation_angle); model.updateResidual(); lim += el_size; } model.dump(); model.dump("cohesive elements"); /// check centers const Array<Real> & fragment_velocity = fragment_manager.getVelocity(); Real initial_position = -L / 2. + el_size / 2.; for (UInt frag = 0; frag < total_nb_fragment; ++frag) { Real theoretical_center = initial_position + el_size * frag; UInt f_index = 0; while (f_index < total_nb_fragment && !Math::are_float_equal(fragment_center(f_index, 0), theoretical_center)) ++f_index; if (f_index == total_nb_fragment) { AKANTU_ERROR("The fragments' center is wrong!"); return EXIT_FAILURE; } f_index = 0; while (f_index < total_nb_fragment && !Math::are_float_equal(fragment_velocity(f_index, 0), theoretical_center)) ++f_index; if (f_index == total_nb_fragment) { AKANTU_ERROR("The fragments' velocity is wrong!"); return EXIT_FAILURE; } } finalize(); if (prank == 0) std::cout << "OK: test_cohesive_buildfragments was passed!" << std::endl; return EXIT_SUCCESS; } void verticalInsertionLimit(SolidMechanicsModelCohesive & model) { UInt spatial_dimension = model.getSpatialDimension(); const Mesh & mesh_facets = model.getMeshFacets(); const Array<Real> & position = mesh_facets.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for(; it != end; ++it) { ElementType type = *it; Array<bool> & check_facets = model.getElementInserter().getCheckFacets(type, ghost_type); const Array<UInt> & connectivity = mesh_facets.getConnectivity(type, ghost_type); UInt nb_nodes_per_facet = connectivity.getNbComponent(); for (UInt f = 0; f < check_facets.getSize(); ++f) { if (!check_facets(f)) continue; UInt nb_aligned_nodes = 1; Real first_node_pos = position(connectivity(f, 0), 0); for (; nb_aligned_nodes < nb_nodes_per_facet; ++nb_aligned_nodes) { Real other_node_pos = position(connectivity(f, nb_aligned_nodes), 0); if (! Math::are_float_equal(first_node_pos, other_node_pos)) break; } if (nb_aligned_nodes != nb_nodes_per_facet) { check_facets(f) = false; } } } } } void displaceElements(SolidMechanicsModelCohesive & model, const Real lim, const Real amount) { UInt spatial_dimension = model.getSpatialDimension(); Array<Real> & displacement = model.getDisplacement(); Mesh & mesh = model.getMesh(); UInt nb_nodes = mesh.getNbNodes(); Array<bool> displaced(nb_nodes); displaced.clear(); Vector<Real> barycenter(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { ElementType type = *it; const Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_element = connectivity.getSize(); UInt nb_nodes_per_element = connectivity.getNbComponent(); Array<UInt>::const_vector_iterator conn_el = connectivity.begin(nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, barycenter.storage(), ghost_type); if (barycenter(0) < lim) { const Vector<UInt> & conn = conn_el[el]; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = conn(n); if (!displaced(node)) { displacement(node, 0) -= amount; displaced(node) = true; } } } } } } } bool isInertiaEqual(const Vector<Real> & a, const Vector<Real> & b) { UInt nb_terms = a.size(); UInt equal_terms = 0; while (equal_terms < nb_terms && std::abs(a(equal_terms) - b(equal_terms)) / a(equal_terms) < Math::getTolerance()) ++equal_terms; return equal_terms == nb_terms; } void rotateArray(Array<Real> & array, Real angle) { UInt spatial_dimension = array.getNbComponent(); Real rotation_values[] = {std::cos(angle), std::sin(angle), 0, -std::sin(angle), std::cos(angle), 0, 0, 0, 1}; Matrix<Real> rotation(rotation_values, spatial_dimension, spatial_dimension); RVector displaced_node(spatial_dimension); - Array<Real>::vector_iterator node_it = array.begin(spatial_dimension); - Array<Real>::vector_iterator node_end = array.end(spatial_dimension); + auto node_it = array.begin(spatial_dimension); + auto node_end = array.end(spatial_dimension); for (; node_it != node_end; ++node_it) { displaced_node.mul<false>(rotation, *node_it); *node_it = displaced_node; } } UInt getNbBigFragments(FragmentManager & fragment_manager, UInt minimum_nb_elements) { fragment_manager.computeNbElementsPerFragment(); const Array<UInt> & nb_elements_per_fragment = fragment_manager.getNbElementsPerFragment(); UInt nb_fragment = fragment_manager.getNbFragment(); UInt nb_big_fragment = 0; for (UInt frag = 0; frag < nb_fragment; ++frag) { if (nb_elements_per_fragment(frag) >= minimum_nb_elements) { ++nb_big_fragment; } } return nb_big_fragment; } diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc index 22ec062bd..e5b0f00ed 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc @@ -1,224 +1,224 @@ /** * @file test_embedded_interface_model_prestress.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Tue Apr 28 2015 * @date last modification: Thu Oct 15 2015 * * @brief Embedded model test for prestressing (bases on stress norm) * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ #include "aka_common.hh" #include "embedded_interface_model.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; #define YG 0.483644859 #define I_eq 0.012488874 #define A_eq (1e-2 + 1. / 7. * 1.) /* -------------------------------------------------------------------------- */ struct StressSolution : public BC::Neumann::FromHigherDim { Real M; Real I; Real yg; Real pre_stress; StressSolution(UInt dim, Real M, Real I, Real yg = 0, Real pre_stress = 0) : BC::Neumann::FromHigherDim(Matrix<Real>(dim, dim)), M(M), I(I), yg(yg), pre_stress(pre_stress) {} virtual ~StressSolution() {} void operator()(const IntegrationPoint & /*quad_point*/, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const { UInt dim = coord.size(); if (dim < 2) AKANTU_ERROR("Solution not valid for 1D"); Matrix<Real> stress(dim, dim); stress.clear(); stress(0, 0) = this->stress(coord(1)); dual.mul<false>(stress, normals); } inline Real stress(Real height) const { return -M / I * (height - yg) + pre_stress; } inline Real neutral_axis() const { return -I * pre_stress / M + yg; } }; /* -------------------------------------------------------------------------- */ int main (int argc, char * argv[]) { initialize("prestress.dat", argc, argv); debug::setDebugLevel(dblError); Math::setTolerance(1e-6); const UInt dim = 2; /* -------------------------------------------------------------------------- */ Mesh mesh(dim); mesh.read("embedded_mesh_prestress.msh"); // mesh.createGroupsFromMeshData<std::string>("physical_names"); Mesh reinforcement_mesh(dim, "reinforcement_mesh"); try { reinforcement_mesh.read("embedded_mesh_prestress_reinforcement.msh"); } catch(debug::Exception & e) {} // reinforcement_mesh.createGroupsFromMeshData<std::string>("physical_names"); EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim); model.initFull(EmbeddedInterfaceModelOptions(_static)); /* -------------------------------------------------------------------------- */ /* Computation of analytical residual */ /* -------------------------------------------------------------------------- */ /* * q = 1000 N/m * L = 20 m * a = 1 m */ Real steel_area = model.getMaterial("reinforcement").get("area"); Real pre_stress = model.getMaterial("reinforcement").get("pre_stress"); Real stress_norm = 0.; StressSolution * concrete_stress = nullptr, * steel_stress = nullptr; Real pre_force = pre_stress * steel_area; Real pre_moment = -pre_force * (YG - 0.25); Real neutral_axis = YG - I_eq / A_eq * pre_force / pre_moment; concrete_stress = new StressSolution(dim, pre_moment, 7. * I_eq, YG, -pre_force / (7. * A_eq)); steel_stress = new StressSolution(dim, pre_moment, I_eq, YG, pre_stress - pre_force / A_eq); stress_norm = std::abs(concrete_stress->stress(1)) * (1 - neutral_axis) * 0.5 + std::abs(concrete_stress->stress(0)) * neutral_axis * 0.5 + std::abs(steel_stress->stress(0.25)) * steel_area; model.applyBC(*concrete_stress, "XBlocked"); auto end_node = *mesh.getElementGroup("EndNode").getNodeGroup().begin(); Vector<Real> end_node_force = model.getForce().begin(dim)[end_node]; end_node_force(0) += steel_stress->stress(0.25) * steel_area; Array<Real> analytical_residual(mesh.getNbNodes(), dim, "analytical_residual"); analytical_residual.copy(model.getForce()); model.getForce().clear(); delete concrete_stress; delete steel_stress; /* -------------------------------------------------------------------------- */ model.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "XBlocked"); model.applyBC(BC::Dirichlet::FixedValue(0.0, _y), "YBlocked"); try { model.solveStep(); } catch (debug::Exception e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } /* -------------------------------------------------------------------------- */ /* Computation of FEM residual norm */ /* -------------------------------------------------------------------------- */ ElementGroup & xblocked = mesh.getElementGroup("XBlocked"); NodeGroup & boundary_nodes = xblocked.getNodeGroup(); NodeGroup::const_node_iterator nodes_it = boundary_nodes.begin(), nodes_end = boundary_nodes.end(); model.assembleInternalForces(); Array<Real> residual(mesh.getNbNodes(), dim, "my_residual"); residual.copy(model.getInternalForce()); residual -= model.getForce(); - Array<Real>::vector_iterator com_res = residual.begin(dim); - Array<Real>::vector_iterator position = mesh.getNodes().begin(dim); + auto com_res = residual.begin(dim); + auto position = mesh.getNodes().begin(dim); Real res_sum = 0.; UInt lower_node = -1; UInt upper_node = -1; Real lower_dist = 1; Real upper_dist = 1; for (; nodes_it != nodes_end ; ++nodes_it) { UInt node_number = *nodes_it; const Vector<Real> res = com_res[node_number]; const Vector<Real> pos = position[node_number]; if (!Math::are_float_equal(pos(1), 0.25)) { if ((std::abs(pos(1) - 0.25) < lower_dist) && (pos(1) < 0.25)) { lower_dist = std::abs(pos(1) - 0.25); lower_node = node_number; } if ((std::abs(pos(1) - 0.25) < upper_dist) && (pos(1) > 0.25)) { upper_dist = std::abs(pos(1) - 0.25); upper_node = node_number; } } for (UInt i = 0 ; i < dim ; i++) { if (!Math::are_float_equal(pos(1), 0.25)) { res_sum += std::abs(res(i)); } } } const Vector<Real> upper_res = com_res[upper_node], lower_res = com_res[lower_node]; const Vector<Real> end_node_res = com_res[end_node]; Vector<Real> delta = upper_res - lower_res; delta *= lower_dist / (upper_dist + lower_dist); Vector<Real> concrete_residual = lower_res + delta; Vector<Real> steel_residual = end_node_res - concrete_residual; for (UInt i = 0 ; i < dim ; i++) { res_sum += std::abs(concrete_residual(i)); res_sum += std::abs(steel_residual(i)); } Real relative_error = std::abs(res_sum - stress_norm) / stress_norm; if (relative_error > 1e-3) { std::cerr << "Relative error = " << relative_error << std::endl; return EXIT_FAILURE; } finalize(); return 0; } diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc index b1f0219b8..f1304ac25 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc @@ -1,61 +1,61 @@ /* -------------------------------------------------------------------------- */ #include "material_neohookean.hh" #include "solid_mechanics_model.hh" #include "test_material_fixtures.hh" #include <gtest/gtest.h> #include <type_traits> /* -------------------------------------------------------------------------- */ using namespace akantu; using types = ::testing::Types< Traits<MaterialNeohookean, 1>, Traits<MaterialNeohookean, 2>, Traits<MaterialNeohookean, 3>>; /*****************************************************************/ template <> void FriendMaterial<MaterialNeohookean<3>>::testComputeStress() { - TO_IMPLEMENT; + AKANTU_TO_IMPLEMENT(); } /*****************************************************************/ template <> void FriendMaterial<MaterialNeohookean<3>>::testComputeTangentModuli() { - TO_IMPLEMENT; + AKANTU_TO_IMPLEMENT(); } /*****************************************************************/ template <> void FriendMaterial<MaterialNeohookean<3>>::testEnergyDensity() { - TO_IMPLEMENT; + AKANTU_TO_IMPLEMENT(); } /*****************************************************************/ namespace { template <typename T> class TestFiniteDefMaterialFixture : public ::TestMaterialFixture<T> {}; TYPED_TEST_CASE(TestFiniteDefMaterialFixture, types); TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeStress) { this->material->testComputeStress(); } TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefEnergyDensity) { this->material->testEnergyDensity(); } TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeTangentModuli) { this->material->testComputeTangentModuli(); } TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputePushWaveSpeed) { this->material->testPushWaveSpeed(); } TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeShearWaveSpeed) { this->material->testShearWaveSpeed(); } } /*****************************************************************/ diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh index d741bb226..f3fd93472 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh @@ -1,184 +1,184 @@ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> #include <random> #include <type_traits> /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ template <typename T> class FriendMaterial : public T { public: ~FriendMaterial() = default; virtual void testComputeStress() { AKANTU_TO_IMPLEMENT(); }; virtual void testComputeTangentModuli() { AKANTU_TO_IMPLEMENT(); }; virtual void testEnergyDensity() { AKANTU_TO_IMPLEMENT(); }; virtual void testPushWaveSpeed() { AKANTU_TO_IMPLEMENT(); } virtual void testShearWaveSpeed() { AKANTU_TO_IMPLEMENT(); } static inline Matrix<Real> getDeviatoricStrain(Real intensity); static inline Matrix<Real> getHydrostaticStrain(Real intensity); static inline const Matrix<Real> reverseRotation(Matrix<Real> mat, Matrix<Real> rotation_matrix) { Matrix<Real> R = rotation_matrix; Matrix<Real> m2 = mat * R; Matrix<Real> m1 = R.transpose(); return m1 * m2; }; static inline const Matrix<Real> applyRotation(Matrix<Real> mat, const Matrix<Real> rotation_matrix) { Matrix<Real> R = rotation_matrix; Matrix<Real> m2 = mat * R.transpose(); Matrix<Real> m1 = R; return m1 * m2; }; static inline Matrix<Real> getRandomRotation3d(); static inline Matrix<Real> getRandomRotation2d(); using T::T; }; /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getDeviatoricStrain(Real intensity) { Matrix<Real> dev = {{0., 1., 2.}, {1., 0., 3.}, {2., 3., 0.}}; dev *= intensity; return dev; } /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getHydrostaticStrain(Real intensity) { Matrix<Real> dev = {{1., 0., 0.}, {0., 2., 0.}, {0., 0., 3.}}; dev *= intensity; return dev; } /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation3d() { constexpr UInt Dim = 3; // Seed with a real random value, if available std::random_device rd; std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::uniform_real_distribution<> dis; Vector<Real> v1(Dim); Vector<Real> v2(Dim); Vector<Real> v3(Dim); for (UInt i = 0; i < Dim; ++i) { v1(i) = dis(gen); v2(i) = dis(gen); } v1.normalize(); v2.normalize(); auto d = v1.dot(v2); v2 -= v1 * d; v2.normalize(); d = v1.dot(v2); v2 -= v1 * d; v2.normalize(); v3.crossProduct(v1, v2); Vector<Real> test_axis(3); test_axis.crossProduct(v1, v2); test_axis -= v3; if (test_axis.norm() > 8 * std::numeric_limits<Real>::epsilon()) { AKANTU_ERROR("The axis vectors do not form a right-handed coordinate " << "system. I. e., ||n1 x n2 - n3|| should be zero, but " << "it is " << test_axis.norm() << "."); } Matrix<Real> mat(Dim, Dim); for (UInt i = 0; i < Dim; ++i) { mat(0, i) = v1[i]; mat(1, i) = v2[i]; mat(2, i) = v3[i]; } return mat; } /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation2d() { constexpr UInt Dim = 2; // Seed with a real random value, if available std::random_device rd; std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::uniform_real_distribution<> dis; // v1 and v2 are such that they form a right-hand basis with prescribed v3, // it's need (at least) for 2d linear elastic anisotropic and (orthotropic) // materials to rotate the tangent stiffness Vector<Real> v1(3); Vector<Real> v2(3); Vector<Real> v3 = {0, 0, 1}; for (UInt i = 0; i < Dim; ++i) { v1(i) = dis(gen); // v2(i) = dis(gen); } v1.normalize(); v2.crossProduct(v3, v1); Matrix<Real> mat(Dim, Dim); for (UInt i = 0; i < Dim; ++i) { mat(0, i) = v1[i]; mat(1, i) = v2[i]; } return mat; } /* -------------------------------------------------------------------------- */ template <typename T, class Model> class TestMaterialBaseFixture : public ::testing::Test { public: using mat_class = typename T::mat_class; void SetUp() override { constexpr auto spatial_dimension = T::Dim; mesh = std::make_unique<Mesh>(spatial_dimension); model = std::make_unique<Model>(*mesh); material = std::make_unique<friend_class>(*model); } void TearDown() override { material.reset(nullptr); model.reset(nullptr); mesh.reset(nullptr); } using friend_class = FriendMaterial<mat_class>; protected: std::unique_ptr<Mesh> mesh; std::unique_ptr<Model> model; std::unique_ptr<friend_class> material; }; /* -------------------------------------------------------------------------- */ template <template <UInt> class T, UInt _Dim> struct Traits { using mat_class = T<_Dim>; static constexpr UInt Dim = _Dim; }; /* -------------------------------------------------------------------------- */ -template <typename T, class Model> +template <typename T> using TestMaterialFixture = TestMaterialBaseFixture<T, SolidMechanicsModel>; /* -------------------------------------------------------------------------- */