diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0206e7bfa..48fde570c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,52 +1,53 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Fri Feb 24 2012 # @date last modification: Tue Sep 23 2014 # # @brief List of examples # # @section LICENSE # # Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free 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 . # # @section DESCRIPTION # #=============================================================================== include_directories( ${AKANTU_INCLUDE_DIRS} ${AKANTU_EXTERNAL_LIB_INCLUDE_DIR} ) #=============================================================================== add_example(new_material "Example on how to add a new material in Akantu" PACKAGE core) add_example(boundary_conditions "Example on hoy to set boundary conditions" PACKAGE core) add_example(explicit "Example on how to run an explicit simulation" PACKAGE core) add_example(io "Example on how to perform Input/Output operations" PACKAGE core) add_example(implicit "Example on how to run an implicit simulation" PACKAGE implicit) -add_example(static "Example on how to run an explicit simulation" PACKAGE implicit) +add_example(static "Example on how to run a static simulation" PACKAGE implicit) add_example(parallel_2d "Example of how to write a parallel code with Akantu" PACKAGE parallel) add_example(cohesive_element "Cohesive element examples" PACKAGE cohesive_element) add_example(contact "Examples on how to use contact within Akantu" PACKAGE contact) add_example(optimization "Optimization examples" PACKAGE optimization) add_example(structural_mechanics "Structural mechanics model examples" PACKAGE structural_mechanics) add_example(heat_transfer "Example on how to run heat transfer simulation" PACKAGE heat_transfer) -#=============================================================================== \ No newline at end of file +add_example(embedded "Example on how to run embedded model simulation" PACKAGE embedded implicit) +#=============================================================================== diff --git a/examples/embedded/CMakeLists.txt b/examples/embedded/CMakeLists.txt new file mode 100644 index 000000000..db215aa62 --- /dev/null +++ b/examples/embedded/CMakeLists.txt @@ -0,0 +1,42 @@ +#=============================================================================== +# @file CMakeLists.txt +# +# @author Lucas Frérot +# +# @date creation: Wed Jul 22 2015 +# @date last modification: Wed Jul 22 2015 +# +# @brief configuration for embedded example +# +# @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 . +# +# @section DESCRIPTION +# +#=============================================================================== + +register_example(embedded embedded.cc USE CGAL) + +add_mesh(concrete_mesh concrete.geo 2 1) +add_mesh(reinforcement_mesh reinforcement.geo 1 1) +add_dependencies(embedded concrete_mesh) +add_dependencies(embedded reinforcement_mesh) + +#=============================================================================== +file(COPY material.dat DESTINATION .) + diff --git a/examples/embedded/concrete.geo b/examples/embedded/concrete.geo new file mode 100644 index 000000000..f4ad04aee --- /dev/null +++ b/examples/embedded/concrete.geo @@ -0,0 +1,24 @@ +// Concrete geometry + +// Target mesh size +lc = 0.3; + +Point(1) = {0, 0, 0, lc}; +Point(2) = {10, 0, 0, lc}; +Point(3) = {10, 1, 0, lc}; +Point(4) = {0, 1, 0, lc}; + +Line(1) = {4, 1}; +Line(2) = {1, 2}; +Line(3) = {2, 3}; +Line(4) = {3, 4}; + +Line Loop(1) = {4, 1, 2, 3}; +Plane Surface(1) = {1}; + +// Boundary conditions +Physical Line("XBlocked") = {3}; +Physical Point("YBlocked") = {1}; +Physical Line("Force") = {4}; + +Physical Surface("concrete") = {1}; diff --git a/examples/embedded/embedded.cc b/examples/embedded/embedded.cc new file mode 100644 index 000000000..3bf33542b --- /dev/null +++ b/examples/embedded/embedded.cc @@ -0,0 +1,108 @@ +/** + * @file embedded.cc + * + * @author Lucas Frérot + * + * @date creation: Wed Jul 22 2015 + * @date last modification: Wed Jul 22 2015 + * + * @brief This code gives an example of a simulation using the embedded model + * + * @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 . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "embedded_interface_model.hh" + +#include +/* -------------------------------------------------------------------------- */ + +using namespace akantu; + +int main(int argc, char * argv[]) { + initialize("material.dat", argc, argv); + + const UInt dim = 2; + + // Loading the concrete mesh + Mesh mesh(dim); + mesh.read("concrete.msh"); + + // Necessary to define physical names + mesh.createGroupsFromMeshData("physical_names"); + + // Loading the reinforcement mesh + Mesh reinforcement_mesh(dim, "reinforcement_mesh"); + + // Exception is raised because reinforcement + // mesh contains only segments, i.e. 1D elements + try { + reinforcement_mesh.read("reinforcement.msh"); + } catch (debug::Exception & e) {} + + // Necessary to define physical names as well + reinforcement_mesh.createGroupsFromMeshData("physical_names"); + + // Model creation + EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim); + model.initFull(EmbeddedInterfaceModelOptions(_static)); + + + // Boundary conditions + model.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "XBlocked"); + model.applyBC(BC::Dirichlet::FixedValue(0.0, _y), "YBlocked"); + + Vector force(dim); + force(0) = 0.0; + force(1) = -1.0; + + model.applyBC(BC::Neumann::FromTraction(force), "Force"); + + // Dumping the concrete + model.setBaseName("concrete"); + model.addDumpFieldVector("displacement"); + model.addDumpFieldVector("force" ); + model.addDumpFieldVector("residual" ); + model.addDumpFieldTensor("stress" ); + + // Dumping the reinforcement + model.setBaseNameToDumper("reinforcement", "reinforcement"); + model.addDumpFieldTensorToDumper("reinforcement", "stress_embedded"); // dumping stress in reinforcement + + // Assemble global stiffness matrix + model.assembleStiffnessMatrix(); + + // Update residual + model.updateResidual(); + + // Solve + Real error; + bool converged = model.solveStep<_scm_newton_raphson_tangent_not_computed, _scc_residual>(1e-6, error, 1); + + if (!converged) + std::cerr << "Model did not converge, error = " << error << std::endl; + + // Dumping model + model.dump(); + model.dump("reinforcement"); + + finalize(); + return EXIT_SUCCESS; +} diff --git a/examples/embedded/material.dat b/examples/embedded/material.dat new file mode 100644 index 000000000..6e8b975f2 --- /dev/null +++ b/examples/embedded/material.dat @@ -0,0 +1,12 @@ +material reinforcement elastic [ + name = reinforcement + E = 210e9 + area = 1e-4 + pre_stress = 10e6 +] + +material elastic [ + name = concrete + E = 30e9 + nu = 0.1 +] diff --git a/examples/embedded/reinforcement.geo b/examples/embedded/reinforcement.geo new file mode 100644 index 000000000..914bde0fe --- /dev/null +++ b/examples/embedded/reinforcement.geo @@ -0,0 +1,11 @@ +// Reinforcement geometry + +// Target mesh size +lc = 1; + +Point(1) = {0, 0.25, 0, lc}; +Point(2) = {10, 0.25, 0, lc}; + +Line(1) = {1, 2}; + +Physical Line("reinforcement") = {1}; diff --git a/extra_packages/extra-materials b/extra_packages/extra-materials index 3a765d092..7cfc6a9a8 160000 --- a/extra_packages/extra-materials +++ b/extra_packages/extra-materials @@ -1 +1 @@ -Subproject commit 3a765d092ea1b310b0810a1098ba227e6a6a5ce8 +Subproject commit 7cfc6a9a8304dc90f0049b0fb3f2d45d30c1bb27 diff --git a/extra_packages/igfem b/extra_packages/igfem index dac505891..8f34e1004 160000 --- a/extra_packages/igfem +++ b/extra_packages/igfem @@ -1 +1 @@ -Subproject commit dac505891dae7b6a6734153dabc9797cce24daf0 +Subproject commit 8f34e1004c34e4485294165aa5990b6dc15b07c7 diff --git a/extra_packages/phase-field b/extra_packages/phase-field index 677e7e81e..7ebb96d17 160000 --- a/extra_packages/phase-field +++ b/extra_packages/phase-field @@ -1 +1 @@ -Subproject commit 677e7e81e2489d8d3f5f64f85b2537695ea41c98 +Subproject commit 7ebb96d17a07df65cce435d92e5487a40479cafc diff --git a/extra_packages/traction-at-split-node-contact b/extra_packages/traction-at-split-node-contact index d5892c7b1..95926b0cf 160000 --- a/extra_packages/traction-at-split-node-contact +++ b/extra_packages/traction-at-split-node-contact @@ -1 +1 @@ -Subproject commit d5892c7b11c25b93cb1a187465032adb45683af7 +Subproject commit 95926b0cfda429a6c2adde41924aa2081892a7ad diff --git a/python/swig/akantu.i b/python/swig/akantu.i index 24acc8c4f..1272c7c39 100644 --- a/python/swig/akantu.i +++ b/python/swig/akantu.i @@ -1,45 +1,48 @@ %module akantu %exception { try { $action } catch (akantu::debug::Exception e) { PyErr_SetString(PyExc_IndexError,e.what()); return NULL; } } %include "stl.i" #define __attribute__(x) %ignore akantu::operator <<; %include "aka_common.i" %include "aka_csr.i" %include "aka_array.i" %define print_self(MY_CLASS) %extend akantu::MY_CLASS { std::string __str__() { std::stringstream sstr; sstr << *($self); return sstr.str(); } } %enddef %include "mesh.i" %include "mesh_utils.i" %include "model.i" %include "solid_mechanics_model.i" +#if defined(AKANTU_COHESIVE_ELEMENT) +%include "solid_mechanics_model_cohesive.i" +#endif #if defined(AKANTU_HEAT_TRANSFER) %include "heat_transfer_model.i" #endif #if defined(AKANTU_STRUCTURAL_MECHANICS) %include "load_functions.i" %include "structural_mechanics_model.i" #endif diff --git a/python/swig/solid_mechanics_model_cohesive.i b/python/swig/solid_mechanics_model_cohesive.i new file mode 100644 index 000000000..46fb19fdf --- /dev/null +++ b/python/swig/solid_mechanics_model_cohesive.i @@ -0,0 +1,13 @@ +%{ +#include "cohesive_element_inserter.hh" +#include "solid_mechanics_model_cohesive.hh" +%} + +namespace akantu { + %ignore SolidMechanicsModelCohesive::initParallel; + %ignore CohesiveElementInserter::initParallel; +} + +%include "cohesive_element_inserter.hh" +%include "solid_mechanics_model_cohesive.hh" + diff --git a/src/mesh/mesh_events.hh b/src/mesh/mesh_events.hh index 336609504..8a8d59900 100644 --- a/src/mesh/mesh_events.hh +++ b/src/mesh/mesh_events.hh @@ -1,145 +1,145 @@ /** * @file mesh_events.hh * * @author Nicolas Richart * * @date Fri Feb 20 10:48:36 2015 * * @brief Classes corresponding to mesh events type * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_EVENTS_HH__ #define __AKANTU_MESH_EVENTS_HH__ template class MeshEvent { public: virtual ~MeshEvent() {} const Array & getList() const { return list; } Array & getList() { return list; } protected: Array list; }; class Mesh; class NewNodesEvent : public MeshEvent { public: virtual ~NewNodesEvent() {}; }; class RemovedNodesEvent : public MeshEvent { public: virtual ~RemovedNodesEvent() {}; inline RemovedNodesEvent(const Mesh & mesh); AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, Array &); AKANTU_GET_MACRO(NewNumbering, new_numbering, const Array &); private: Array new_numbering; }; class NewElementsEvent : public MeshEvent { public: virtual ~NewElementsEvent() {}; }; class RemovedElementsEvent : public MeshEvent { public: virtual ~RemovedElementsEvent() {}; inline RemovedElementsEvent(const Mesh & mesh, ID new_numbering_id = "new_numbering"); AKANTU_GET_MACRO(NewNumbering, new_numbering, const ElementTypeMapArray &); AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, ElementTypeMapArray &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(NewNumbering, new_numbering, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(NewNumbering, new_numbering, UInt); protected: ElementTypeMapArray new_numbering; }; class ChangedElementsEvent : public RemovedElementsEvent { public: virtual ~ChangedElementsEvent() {}; inline ChangedElementsEvent(const Mesh & mesh, ID new_numbering_id = "changed_event:new_numbering") : RemovedElementsEvent(mesh, new_numbering_id) {}; AKANTU_GET_MACRO(ListOld, list, const Array &); AKANTU_GET_MACRO_NOT_CONST(ListOld, list, Array &); AKANTU_GET_MACRO(ListNew, new_list, const Array &); AKANTU_GET_MACRO_NOT_CONST(ListNew, new_list, Array &); protected: Array new_list; }; /* -------------------------------------------------------------------------- */ class MeshEventHandler { public: virtual ~MeshEventHandler() {}; /* ------------------------------------------------------------------------ */ /* Internal code */ /* ------------------------------------------------------------------------ */ private: inline void sendEvent(const NewNodesEvent & event) { onNodesAdded (event.getList(), event); } inline void sendEvent(const RemovedNodesEvent & event) { onNodesRemoved(event.getList(), event.getNewNumbering(), event); } inline void sendEvent(const NewElementsEvent & event) { onElementsAdded (event.getList(), event); } inline void sendEvent(const RemovedElementsEvent & event) { onElementsRemoved(event.getList(), event.getNewNumbering(), event); } inline void sendEvent(const ChangedElementsEvent & event) { onElementsChanged(event.getListOld(), event.getListNew(), event.getNewNumbering(), event); } template friend class EventHandlerManager; /* ------------------------------------------------------------------------ */ /* Interface */ /* ------------------------------------------------------------------------ */ public: virtual void onNodesAdded (const Array & nodes_list, const NewNodesEvent & event) = 0; virtual void onNodesRemoved(const Array & nodes_list, const Array & new_numbering, const RemovedNodesEvent & event) = 0; virtual void onElementsAdded (__attribute__((unused)) const Array & elements_list, - __attribute__((unused)) const NewElementsEvent & event) { } + __attribute__((unused)) const NewElementsEvent & event) = 0; virtual void onElementsRemoved(__attribute__((unused)) const Array & elements_list, __attribute__((unused)) const ElementTypeMapArray & new_numbering, - __attribute__((unused)) const RemovedElementsEvent & event) { } + __attribute__((unused)) const RemovedElementsEvent & event) = 0; virtual void onElementsChanged(__attribute__((unused)) const Array & old_elements_list, __attribute__((unused)) const Array & new_elements_list, __attribute__((unused)) const ElementTypeMapArray & new_numbering, - __attribute__((unused)) const ChangedElementsEvent & event) { } + __attribute__((unused)) const ChangedElementsEvent & event) = 0; }; #endif /* __AKANTU_MESH_EVENTS_HH__ */ diff --git a/src/model/common/neighborhood_base.cc b/src/model/common/neighborhood_base.cc index df7e1528f..9b624f8b1 100644 --- a/src/model/common/neighborhood_base.cc +++ b/src/model/common/neighborhood_base.cc @@ -1,292 +1,293 @@ /** * @file neighborhood_base.cc * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Thu Oct 8 15:40:36 2015 * * @brief Implementation of generic neighborhood base * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ NeighborhoodBase::NeighborhoodBase(const SolidMechanicsModel & model, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), model(model), neighborhood_radius(0.), spatial_grid(NULL), is_creating_grid(false), grid_synchronizer(NULL), quad_coordinates(quad_coordinates), spatial_dimension(this->model.getSpatialDimension()), synch_registry(NULL) { AKANTU_DEBUG_IN(); this->createSynchronizerRegistry(this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NeighborhoodBase::~NeighborhoodBase() { AKANTU_DEBUG_IN(); delete spatial_grid; delete grid_synchronizer; delete synch_registry; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::createSynchronizerRegistry(DataAccessor * data_accessor){ this->synch_registry = new SynchronizerRegistry(*data_accessor); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::initNeighborhood() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Creating the grid"); this->createGrid(); AKANTU_DEBUG_OUT(); } /* ------------------------------------------------------------------------- */ void NeighborhoodBase::createGrid() { AKANTU_DEBUG_IN(); const Real safety_factor = 1.2; // for the cell grid spacing Mesh & mesh = this->model.getMesh(); mesh.computeBoundingBox(); const Vector & lower_bounds = mesh.getLocalLowerBounds(); const Vector & upper_bounds = mesh.getLocalUpperBounds(); Vector center = 0.5 * (upper_bounds + lower_bounds); Vector spacing(spatial_dimension, this->neighborhood_radius * safety_factor); spatial_grid = new SpatialGrid(spatial_dimension, spacing, center); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::updatePairList() { AKANTU_DEBUG_IN(); //// loop over all quads -> all cells SpatialGrid::cells_iterator cell_it = spatial_grid->beginCells(); SpatialGrid::cells_iterator cell_end = spatial_grid->endCells(); Vector q1_coords(spatial_dimension); Vector q2_coords(spatial_dimension); IntegrationPoint q1; IntegrationPoint q2; UInt counter = 0; for (; cell_it != cell_end; ++cell_it) { AKANTU_DEBUG_INFO("Looping on next cell"); SpatialGrid::Cell::iterator first_quad = spatial_grid->beginCell(*cell_it); SpatialGrid::Cell::iterator last_quad = spatial_grid->endCell(*cell_it); for (;first_quad != last_quad; ++first_quad, ++counter){ q1 = *first_quad; if (q1.ghost_type == _ghost) break; Array::const_vector_iterator coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type).begin(spatial_dimension); q1_coords = coords_type_1_it[q1.global_num]; AKANTU_DEBUG_INFO("Current quadrature point in this cell: " << q1); SpatialGrid::CellID cell_id = spatial_grid->getCellID(q1_coords); /// loop over all the neighbouring cells of the current quad SpatialGrid::neighbor_cells_iterator first_neigh_cell = spatial_grid->beginNeighborCells(cell_id); SpatialGrid::neighbor_cells_iterator last_neigh_cell = spatial_grid->endNeighborCells(cell_id); for (; first_neigh_cell != last_neigh_cell; ++first_neigh_cell) { SpatialGrid::Cell::iterator first_neigh_quad = spatial_grid->beginCell(*first_neigh_cell); SpatialGrid::Cell::iterator last_neigh_quad = spatial_grid->endCell(*first_neigh_cell); // loop over the quadrature point in the current neighboring cell for (;first_neigh_quad != last_neigh_quad; ++first_neigh_quad){ q2 = *first_neigh_quad; Array::const_vector_iterator coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type).begin(spatial_dimension); q2_coords = coords_type_2_it[q2.global_num]; Real distance = q1_coords.distance(q2_coords); if(distance <= this->neighborhood_radius + Math::getTolerance() && (q2.ghost_type == _ghost || (q2.ghost_type == _not_ghost && q1.global_num <= q2.global_num))) { // storing only half lists pair_list[q2.ghost_type].push_back(std::make_pair(q1, q2)); } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::savePairs(const std::string & filename) const { std::ofstream pout; std::stringstream sstr; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); for(;first_pair != last_pair; ++first_pair) { const IntegrationPoint & q1 = first_pair->first; const IntegrationPoint & q2 = first_pair->second; pout << q1 << " " << q2 << " " << std::endl; } } } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::saveNeighborCoords(const std::string & filename) const { /// this function is not optimazed and only used for tests on small meshes /// @todo maybe optimize this function for better performance? Vector q1_coords(spatial_dimension); Vector q2_coords(spatial_dimension); IntegrationPoint q1; IntegrationPoint q2; std::ofstream pout; std::stringstream sstr; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); /// loop over all the quads and write the position of their neighbors SpatialGrid::cells_iterator cell_it = spatial_grid->beginCells(); SpatialGrid::cells_iterator cell_end = spatial_grid->endCells(); for (; cell_it != cell_end; ++cell_it) { SpatialGrid::Cell::iterator first_quad = spatial_grid->beginCell(*cell_it); SpatialGrid::Cell::iterator last_quad = spatial_grid->endCell(*cell_it); for (;first_quad != last_quad; ++first_quad){ q1 = *first_quad; Array::const_vector_iterator coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type).begin(spatial_dimension); q1_coords = coords_type_1_it[q1.global_num]; pout << "#neighbors for quad " << q1.global_num << std::endl; pout << q1_coords << std::endl; for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); for(;first_pair != last_pair; ++first_pair) { if (q1 == first_pair->first && first_pair->second != q1) { q2 = first_pair->second; Array::const_vector_iterator coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type).begin(spatial_dimension); q2_coords = coords_type_2_it[q2.global_num]; pout << q2_coords << std::endl; } if (q1 == first_pair->second && first_pair->first != q1) { q2 = first_pair->first; Array::const_vector_iterator coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type).begin(spatial_dimension); q2_coords = coords_type_2_it[q2.global_num]; pout << q2_coords << std::endl; } } } } } } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = 0; // Change the pairs in new global numbering for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; PairList::iterator first_pair = pair_list[ghost_type2].begin(); PairList::iterator last_pair = pair_list[ghost_type2].end(); for(;first_pair != last_pair; ++first_pair) { IntegrationPoint & q1 = first_pair->first; if(new_numbering.exists(q1.type, q1.ghost_type)) { UInt q1_new_el = new_numbering(q1.type, q1.ghost_type)(q1.element); AKANTU_DEBUG_ASSERT(q1_new_el != UInt(-1), "A local quadrature_point as been removed instead of just being renumbered"); q1.element = q1_new_el; nb_quad = fem.getNbIntegrationPoints(q1.type, q1.ghost_type); q1.global_num = nb_quad * q1.element + q1.num_point; } IntegrationPoint & q2 = first_pair->second; if(new_numbering.exists(q2.type, q2.ghost_type)) { UInt q2_new_el = new_numbering(q2.type, q2.ghost_type)(q2.element); AKANTU_DEBUG_ASSERT(q2_new_el != UInt(-1), "A local quadrature_point as been removed instead of just being renumbered"); q2.element = q2_new_el; nb_quad = fem.getNbIntegrationPoints(q2.type, q2.ghost_type); q2.global_num = nb_quad * q2.element + q2.num_point; } } } this->grid_synchronizer->onElementsRemoved(element_list, new_numbering, event); AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/model/common/neighborhood_base.hh b/src/model/common/neighborhood_base.hh index f561ed628..bacc6bf2f 100644 --- a/src/model/common/neighborhood_base.hh +++ b/src/model/common/neighborhood_base.hh @@ -1,147 +1,149 @@ /** * @file neighborhood_base.hh * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Thu Oct 8 15:27:33 2015 * * @brief Generic neighborhood of quadrature points * * @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 . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NEIGHBORHOOD_BASE_HH__ #define __AKANTU_NEIGHBORHOOD_BASE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "aka_grid_dynamic.hh" #include "grid_synchronizer.hh" #include "aka_memory.hh" #include "data_accessor.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class NeighborhoodBase : public Memory, public DataAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NeighborhoodBase(const SolidMechanicsModel & model, const ElementTypeMapReal & quad_coordinates, const ID & id = "neighborhood", const MemoryID & memory_id = 0); virtual ~NeighborhoodBase(); typedef std::vector< std::pair > PairList; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// intialize the neighborhood virtual void initNeighborhood(); /// create a synchronizer registry void createSynchronizerRegistry(DataAccessor * data_accessor); /// initialize the material computed parameter inline void insertQuad(const IntegrationPoint & quad, const Vector & coords); /// create the pairs of quadrature points void updatePairList(); /// save the pairs of quadrature points in a file void savePairs(const std::string & filename) const; /// save the coordinates of all neighbors of a quad void saveNeighborCoords(const std::string & filename) const; /// create grid synchronizer and exchange ghost cells virtual void createGridSynchronizer() = 0; /// inherited function from MeshEventHandler virtual void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event); protected: /// create the grid void createGrid(); /* -------------------------------------------------------------------------- */ /* Accessors */ /* -------------------------------------------------------------------------- */ public: AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); AKANTU_GET_MACRO(Model, model, const SolidMechanicsModel &); /// return the object handling synchronizers AKANTU_GET_MACRO(SynchronizerRegistry, *synch_registry, SynchronizerRegistry &); + AKANTU_GET_MACRO(PairLists, pair_list, const PairList *); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the model to which the neighborhood belongs const SolidMechanicsModel & model; /// Radius of impact: to determine if two quadrature points influence each other Real neighborhood_radius; /** * the pairs of quadrature points * 0: not ghost to not ghost * 1: not ghost to ghost */ PairList pair_list[2]; /// the regular grid to construct/update the pair lists SpatialGrid * spatial_grid; bool is_creating_grid; /// the grid synchronizer for parallel computations GridSynchronizer * grid_synchronizer; /// the quadrature point positions const ElementTypeMapReal & quad_coordinates; /// the spatial dimension of the problem const UInt spatial_dimension; /// synchronizer registry SynchronizerRegistry * synch_registry; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "neighborhood_base_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_NEIGHBORHOOD_BASE_HH__ */ diff --git a/src/model/common/neighborhood_base_inline_impl.cc b/src/model/common/neighborhood_base_inline_impl.cc index 2ae71b8b8..8464f1a8e 100644 --- a/src/model/common/neighborhood_base_inline_impl.cc +++ b/src/model/common/neighborhood_base_inline_impl.cc @@ -1,44 +1,45 @@ /** * @file neighborhood_base_inline_impl.cc * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Mon Sep 21 18:25:31 2015 * * @brief Inline implementation of neighborhood base functions * * @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 . * */ /* -------------------------------------------------------------------------- */ __END_AKANTU__ //// includes /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ inline void NeighborhoodBase::insertQuad(const IntegrationPoint & quad, const Vector & coords) { this->spatial_grid->insert(quad, coords); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ 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 7716df588..d9c47abd4 100644 --- a/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc +++ b/src/model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc @@ -1,311 +1,311 @@ /** * @file neighborhood_max_criterion.cc * @author Aurelia Isabel Cuba Ramos * @date Wed Oct 14 21:31:07 2015 * * @brief Implementation of class NeighborhoodMaxCriterion * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "neighborhood_max_criterion.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ NeighborhoodMaxCriterion::NeighborhoodMaxCriterion(const SolidMechanicsModel & model, const ElementTypeMapReal & quad_coordinates, const ID & criterion_id, const ID & id, const MemoryID & memory_id) : NeighborhoodBase(model, quad_coordinates, id, memory_id), Parsable(_st_non_local, id), is_highest("is_highest", id), criterion(criterion_id, 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).getSize(); 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).getSize(); 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(_st_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 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 tags; tags.insert(_gst_nh_criterion); std::stringstream sstr; sstr << getID() << ":grid_synchronizer"; this->grid_synchronizer = GridSynchronizer::createGridSynchronizer(this->model.getMesh(), *spatial_grid, sstr.str(), synch_registry, tags, 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 & quads = this->quad_coordinates(*it, ghost_type); q.type = *it; Array::const_vector_iterator 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 & max_quads) { AKANTU_DEBUG_IN(); /// clear the element type maps this->is_highest.clear(); this->criterion.clear(); /// update the values of the criterion const ID field_name = criterion.getName(); for (UInt m = 0; m < this->model.getNbMaterials(); ++m) { const Material & material = this->model.getMaterial(m); - if (material.isInternal(field_name, _ek_regular)) + if (material.isInternal(field_name, _ek_regular)) for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType ghost_type = (GhostType) g; material.flattenInternal(field_name, criterion, ghost_type, _ek_regular); } } /// start the exchange the value of the criterion on the ghost elements SynchronizerRegistry & synch_registry = this->model.getSynchronizerRegistry(); synch_registry.asynchronousSynchronize(_gst_nh_criterion); /// compare to not-ghost neighbors checkNeighbors(_not_ghost); /// finish the exchange synch_registry.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::const_scalar_iterator is_highest_it = is_highest(*it, _not_ghost).begin(); Array::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 & has_highest_eq_stress_1 = is_highest(lq1.type, lq1.ghost_type); const Array & criterion_1 = this->criterion(lq1.type, lq1.ghost_type); const Array & 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 & 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 & nb_ghost_protected) { Mesh & mesh = this->model.getMesh(); /// create remove elements event RemovedElementsEvent remove_elem(mesh); /// create set of ghosts to keep std::set 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 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; std::set::const_iterator 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 & 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); } __END_AKANTU__ diff --git a/src/model/common/non_local_toolbox/non_local_manager.cc b/src/model/common/non_local_toolbox/non_local_manager.cc index 6359b9fbb..c6cc622bd 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.cc +++ b/src/model/common/non_local_toolbox/non_local_manager.cc @@ -1,634 +1,636 @@ /** * @file non_local_manager.cc * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Mon Sep 21 15:32:10 2015 * * @brief Implementation of non-local 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 . * */ /* -------------------------------------------------------------------------- */ #include "non_local_manager.hh" #include "non_local_neighborhood.hh" #include "material_non_local.hh" #include "base_weight_function.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ NonLocalManager::NonLocalManager(SolidMechanicsModel & model, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), Parsable(_st_neighborhoods, id), model(model), quad_positions("quad_positions", id), volumes("volumes", id), spatial_dimension(this->model.getSpatialDimension()), compute_stress_calls(0), dummy_registry(NULL), dummy_grid(NULL) { Mesh & mesh = this->model.getMesh(); mesh.registerEventHandler(*this); /// initialize the element type map array /// it will be resized to nb_quad * nb_element during the computation of coords mesh.initElementTypeMapArray(quad_positions, spatial_dimension, spatial_dimension, false, _ek_regular, true); + this->initElementTypeMap(1, volumes, this->model.getFEEngine()); /// parse the neighborhood information from the input file const Parser & parser = getStaticParser(); /// iterate over all the non-local sections and store them in a map std::pair weight_sect = parser.getSubSections(_st_non_local); Parser::const_section_iterator it = weight_sect.first; for (; it != weight_sect.second; ++it) { const ParserSection & section = *it; ID name = section.getName(); this->weight_function_types[name] = section; } this->dummy_registry = new SynchronizerRegistry(this->dummy_accessor); } /* -------------------------------------------------------------------------- */ NonLocalManager::~NonLocalManager() { /// delete neighborhoods NeighborhoodMap::iterator it; for (it = neighborhoods.begin(); it != neighborhoods.end(); ++it) { if(it->second) delete it->second; } /// delete non-local variables std::map::iterator it_variables; for (it_variables = non_local_variables.begin(); it_variables != non_local_variables.end(); ++it_variables) { if(it_variables->second) delete it_variables->second; } std::map::iterator it_internals; for (it_internals = weight_function_internals.begin(); it_internals != weight_function_internals.end(); ++it_internals) { if(it_internals->second) delete it_internals->second; } std::map::iterator grid_synch_it; for (grid_synch_it = dummy_synchronizers.begin(); grid_synch_it != dummy_synchronizers.end(); ++grid_synch_it) { if(grid_synch_it->second) delete grid_synch_it->second; } /// delete all objects related to the dummy synchronizers delete dummy_registry; delete dummy_grid; } /* -------------------------------------------------------------------------- */ void NonLocalManager::setJacobians(const FEEngine & fe_engine, const ElementKind & kind) { Mesh & mesh = this->model.getMesh(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, kind); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, gt, kind); for(; it != last_type; ++it) { jacobians(*it, gt) = &fe_engine.getIntegratorInterface().getJacobians(*it, gt); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhood(const ID & weight_func, const ID & neighborhood_id) { AKANTU_DEBUG_IN(); const ParserSection & section = this->weight_function_types[weight_func]; const ID weight_func_type = section.getOption(); /// create new neighborhood for given ID std::stringstream sstr; sstr << id << ":neighborhood:" << neighborhood_id; if (weight_func_type == "base_wf") neighborhoods[neighborhood_id] = new NonLocalNeighborhood(*this, this->quad_positions, sstr.str()); else if (weight_func_type == "remove_wf") neighborhoods[neighborhood_id] = new NonLocalNeighborhood(*this, this->quad_positions, sstr.str()); else if (weight_func_type == "stress_wf") neighborhoods[neighborhood_id] = new NonLocalNeighborhood(*this, this->quad_positions, sstr.str()); else if (weight_func_type == "damage_wf") neighborhoods[neighborhood_id] = new NonLocalNeighborhood(*this, this->quad_positions, sstr.str()); else AKANTU_EXCEPTION("error in weight function type provided in material file"); neighborhoods[neighborhood_id]->parseSection(section); neighborhoods[neighborhood_id]->initNeighborhood(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhoodSynchronizers() { /// exchange all the neighborhood IDs, so that every proc knows how many neighborhoods exist globally /// First: Compute locally the maximum ID size UInt max_id_size = 0; UInt current_size = 0; NeighborhoodMap::const_iterator it; for (it = neighborhoods.begin(); it != neighborhoods.end(); ++it) { current_size = it->first.size(); if (current_size > max_id_size) max_id_size = current_size; } /// get the global maximum ID size on each proc StaticCommunicator & static_communicator = akantu::StaticCommunicator::getStaticCommunicator(); static_communicator.allReduce(&max_id_size, 1, _so_max); /// get the rank for this proc and the total nb proc UInt prank = static_communicator.whoAmI(); UInt psize = static_communicator.getNbProc(); /// exchange the number of neighborhoods on each proc Array nb_neighborhoods_per_proc(psize); nb_neighborhoods_per_proc(prank) = neighborhoods.size(); static_communicator.allGather(nb_neighborhoods_per_proc.storage(), 1); /// compute the total number of neighborhoods UInt nb_neighborhoods_global = std::accumulate(nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.end(), 0); /// allocate an array of chars to store the names of all neighborhoods Array buffer(nb_neighborhoods_global, max_id_size); /// starting index on this proc UInt starting_index = std::accumulate(nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.begin() + prank, 0); it = neighborhoods.begin(); /// store the names of local neighborhoods in the buffer for (UInt i = 0; i < neighborhoods.size(); ++i, ++it) { UInt c = 0; for (; c < it->first.size(); ++c) buffer(i + starting_index, c) = it->first[c]; for (; c < max_id_size; ++c) buffer(i + starting_index, c) = char( 0 ); } /// store the nb of data to send in the all gather Array buffer_size(nb_neighborhoods_per_proc); buffer_size *= max_id_size; /// exchange the names of all the neighborhoods with all procs static_communicator.allGatherV(buffer.storage(), buffer_size.storage()); for (UInt i = 0; i < nb_neighborhoods_global; ++i) { std::stringstream neighborhood_id; for(UInt c = 0; c < max_id_size; ++c) { if (buffer(i,c) == char( 0 )) break; neighborhood_id << buffer(i,c); } global_neighborhoods.insert(neighborhood_id.str()); } /// this proc does not know all the neighborhoods -> create dummy /// grid so that this proc can participate in the all gather for /// detecting the overlap of neighborhoods this proc doesn't know Vector grid_center(this->spatial_dimension); for(UInt s = 0; s < this->spatial_dimension; ++s) grid_center(s) = std::numeric_limits::max(); dummy_grid = new SpatialGrid(spatial_dimension, 0., grid_center); std::set tags; tags.insert(_gst_mnl_for_average); tags.insert(_gst_mnl_weight); std::set::const_iterator global_neighborhoods_it = global_neighborhoods.begin(); for (; global_neighborhoods_it != global_neighborhoods.end(); ++global_neighborhoods_it) { it = neighborhoods.find(*global_neighborhoods_it); if (it != neighborhoods.end()) { it->second->createGridSynchronizer(); } else { ID neighborhood_name = *global_neighborhoods_it; std::stringstream sstr; sstr << getID() << ":" << neighborhood_name << ":grid_synchronizer"; dummy_synchronizers[neighborhood_name] = GridSynchronizer::createGridSynchronizer(this->model.getMesh(), *dummy_grid, sstr.str(), dummy_registry, tags, 0, false); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::flattenInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (UInt m = 0; m < this->non_local_materials.size(); ++m) { Material & material = *(this->non_local_materials[m]); - if (material.isInternal(field_name, kind)) + if (material.isInternal(field_name, kind)) material.flattenInternal(field_name, internal_flat, ghost_type, kind); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::averageInternals(const GhostType & ghost_type) { /// update the weights of the weight function if (ghost_type == _not_ghost) this->computeWeights(); /// loop over all neighborhoods and compute the non-local variables NeighborhoodMap::iterator neighborhood_it = neighborhoods.begin(); NeighborhoodMap::iterator neighborhood_end = neighborhoods.end(); for (; neighborhood_it != neighborhood_end; ++neighborhood_it) { /// loop over all the non-local variables of the given neighborhood std::map::iterator non_local_variable_it = non_local_variables.begin(); std::map::iterator non_local_variable_end = non_local_variables.end(); for(; non_local_variable_it != non_local_variable_end; ++non_local_variable_it) { NonLocalVariable * non_local_var = non_local_variable_it->second; neighborhood_it->second->weightedAverageOnNeighbours(non_local_var->local, non_local_var->non_local, non_local_var->nb_component, ghost_type); } } if (ghost_type == _ghost) { /// compute the non-local stresses in the materials for(UInt m = 0; m < this->non_local_materials.size(); ++m) { switch (spatial_dimension) { case 1: dynamic_cast &>(*(this->non_local_materials[m])).computeNonLocalStresses(_not_ghost); break; case 2: dynamic_cast &>(*(this->non_local_materials[m])).computeNonLocalStresses(_not_ghost); break; case 3: dynamic_cast &>(*(this->non_local_materials[m])).computeNonLocalStresses(_not_ghost); break; } } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::init(){ /// store the number of current ghost elements for each type in the mesh ElementTypeMap 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); /// exchange the missing ghosts for the non-local neighborhoods this->createNeighborhoodSynchronizers(); /// insert the ghost quadrature points of the non-local materials into the non-local neighborhoods for(UInt m = 0; m < this->non_local_materials.size(); ++m) { switch (spatial_dimension) { case 1: dynamic_cast &>(*(this->non_local_materials[m])).insertQuadsInNeighborhoods(_ghost); break; case 2: dynamic_cast &>(*(this->non_local_materials[m])).insertQuadsInNeighborhoods(_ghost); break; case 3: dynamic_cast &>(*(this->non_local_materials[m])).insertQuadsInNeighborhoods(_ghost); break; } } FEEngine & fee = this->model.getFEEngine(); this->updatePairLists(); /// cleanup the unneccessary ghost elements this->cleanupExtraGhostElements(nb_ghost_protected); - this->initElementTypeMap(1, volumes, fee); this->setJacobians(fee, _ek_regular); this->initNonLocalVariables(); this->computeWeights(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::initNonLocalVariables(){ /// loop over all the non-local variables std::map::iterator non_local_variable_it = non_local_variables.begin(); std::map::iterator non_local_variable_end = non_local_variables.end(); for(; non_local_variable_it != non_local_variable_end; ++non_local_variable_it) { NonLocalVariable & variable = *(non_local_variable_it->second); this->initElementTypeMap(variable.nb_component, variable.non_local, this->model.getFEEngine()); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::initElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { Mesh & mesh = this->model.getMesh(); /// need to resize the arrays for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, el_kind); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, el_kind); for(; it != end; ++it) { ElementType el_type = *it; UInt nb_element = mesh.getNbElement(*it, gt); UInt nb_quads = fee.getNbIntegrationPoints(*it, gt); if (!element_map.exists(el_type, gt)) { element_map.alloc(nb_element * nb_quads, nb_component, el_type, gt); } } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::distributeInternals(ElementKind kind) { /// loop over all the non-local variables and copy back their values into the materials std::map::iterator non_local_variable_it = non_local_variables.begin(); std::map::iterator non_local_variable_end = non_local_variables.end(); for(; non_local_variable_it != non_local_variable_end; ++non_local_variable_it) { NonLocalVariable * non_local_var = non_local_variable_it->second; const ID field_name = non_local_var->non_local.getName(); /// loop over all the materials for (UInt m = 0; m < this->non_local_materials.size(); ++m) { - if (this->non_local_materials[m]->isInternal(field_name, kind)) + if (this->non_local_materials[m]->isInternal(field_name, kind)) switch (spatial_dimension) { case 1: dynamic_cast &>(*(this->non_local_materials[m])).updateNonLocalInternals(non_local_var->non_local, field_name, non_local_var->nb_component); break; case 2: dynamic_cast &>(*(this->non_local_materials[m])).updateNonLocalInternals(non_local_var->non_local, field_name, non_local_var->nb_component); break; case 3: dynamic_cast &>(*(this->non_local_materials[m])).updateNonLocalInternals(non_local_var->non_local, field_name, non_local_var->nb_component); break; } } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::computeAllNonLocalStresses() { /// update the flattened version of the internals std::map::iterator non_local_variable_it = non_local_variables.begin(); std::map::iterator non_local_variable_end = non_local_variables.end(); for(; non_local_variable_it != non_local_variable_end; ++non_local_variable_it) { non_local_variable_it->second->local.clear(); non_local_variable_it->second->non_local.clear(); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; this->flattenInternal(non_local_variable_it->second->local, ghost_type, _ek_regular); } } this->volumes.clear(); ///loop over all the neighborhoods and compute intiate the /// exchange of the non-local_variables // std::set::const_iterator global_neighborhood_it = global_neighborhoods.begin(); // NeighborhoodMap::iterator it; // for(; global_neighborhood_it != global_neighborhoods.end(); ++global_neighborhood_it) { // it = neighborhoods.find(*global_neighborhood_it); // if (it != neighborhoods.end()) // it->second->getSynchronizerRegistry().asynchronousSynchronize(_gst_mnl_for_average); // else // dummy_synchronizers[*global_neighborhood_it]->asynchronousSynchronize(dummy_accessor, _gst_mnl_for_average); // } NeighborhoodMap::iterator neighborhood_it = neighborhoods.begin(); NeighborhoodMap::iterator neighborhood_end = neighborhoods.end(); for(; neighborhood_it != neighborhoods.end(); ++neighborhood_it) { neighborhood_it->second->getSynchronizerRegistry().asynchronousSynchronize(_gst_mnl_for_average); } this->averageInternals(_not_ghost); AKANTU_DEBUG_INFO("Wait distant non local stresses"); /// loop over all the neighborhoods and block until all non-local /// variables have been exchanged // global_neighborhood_it = global_neighborhoods.begin(); // for(; global_neighborhood_it != global_neighborhoods.end(); ++global_neighborhood_it) { // it = neighborhoods.find(*global_neighborhood_it); // if (it != neighborhoods.end()) // it->second->getSynchronizerRegistry().waitEndSynchronize(_gst_mnl_for_average); // else // dummy_synchronizers[*global_neighborhood_it]->waitEndSynchronize(dummy_accessor, _gst_mnl_for_average); // } neighborhood_it = neighborhoods.begin(); for(; neighborhood_it != neighborhoods.end(); ++neighborhood_it) { neighborhood_it->second->getSynchronizerRegistry().waitEndSynchronize(_gst_mnl_for_average); } this->averageInternals(_ghost); /// copy the results in the materials this->distributeInternals(_ek_regular); /// loop over all the materials and update the weights for (UInt m = 0; m < this->non_local_materials.size(); ++m) { switch (spatial_dimension) { case 1: dynamic_cast &>(*(this->non_local_materials[m])).computeNonLocalStresses(_not_ghost); break; case 2: dynamic_cast &>(*(this->non_local_materials[m])).computeNonLocalStresses(_not_ghost); break; case 3: dynamic_cast &>(*(this->non_local_materials[m])).computeNonLocalStresses(_not_ghost); break; } } ++this->compute_stress_calls; } /* -------------------------------------------------------------------------- */ void NonLocalManager::cleanupExtraGhostElements(ElementTypeMap & nb_ghost_protected) { typedef std::set ElementSet; ElementSet relevant_ghost_elements; ElementSet to_keep_per_neighborhood; /// loop over all the neighborhoods and get their protected ghosts NeighborhoodMap::iterator neighborhood_it = neighborhoods.begin(); NeighborhoodMap::iterator neighborhood_end = neighborhoods.end(); for (; neighborhood_it != neighborhood_end; ++neighborhood_it) { neighborhood_it->second->cleanupExtraGhostElements(to_keep_per_neighborhood); ElementSet::const_iterator it = to_keep_per_neighborhood.begin(); for(; it != to_keep_per_neighborhood.end(); ++it) relevant_ghost_elements.insert(*it); to_keep_per_neighborhood.clear(); } /// remove all unneccessary ghosts from the mesh /// Create list of element to remove and new numbering for element to keep Mesh & mesh = this->model.getMesh(); ElementSet ghost_to_erase; Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); RemovedElementsEvent remove_elem(mesh); Element element; element.ghost_type = _ghost; for(; it != last_type; ++it) { element.type = *it; UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); UInt nb_ghost_elem_protected = 0; try { nb_ghost_elem_protected = nb_ghost_protected(*it, _ghost); } catch (...) {} if(!remove_elem.getNewNumbering().exists(*it, _ghost)) remove_elem.getNewNumbering().alloc(nb_ghost_elem, 1, *it, _ghost); else remove_elem.getNewNumbering(*it, _ghost).resize(nb_ghost_elem); Array & 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) == relevant_ghost_elements.end()) { remove_elem.getList().push_back(element); new_numbering(element.element) = UInt(-1); } } /// renumber remaining ghosts UInt ng = 0; for (UInt g = 0; g < nb_ghost_elem; ++g) { if (new_numbering(g) != UInt(-1)) { new_numbering(g) = ng; ++ng; } } } it = mesh.firstType(spatial_dimension, _not_ghost); last_type = mesh.lastType(spatial_dimension, _not_ghost); for(; it != last_type; ++it) { UInt nb_elem = mesh.getNbElement(*it, _not_ghost); if(!remove_elem.getNewNumbering().exists(*it, _not_ghost)) remove_elem.getNewNumbering().alloc(nb_elem, 1, *it, _not_ghost); Array & new_numbering = remove_elem.getNewNumbering(*it, _not_ghost); for (UInt e = 0; e < nb_elem; ++e) { new_numbering(e) = e; } } mesh.sendEvent(remove_elem); } /* -------------------------------------------------------------------------- */ void NonLocalManager::onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { FEEngine & fee = this->model.getFEEngine(); this->removeIntegrationPointsFromMap(event.getNewNumbering(), spatial_dimension, quad_positions, fee, _ek_regular); this->removeIntegrationPointsFromMap(event.getNewNumbering(), 1, volumes, fee, _ek_regular); /// loop over all the neighborhoods and call onElementsRemoved std::set::const_iterator global_neighborhood_it = global_neighborhoods.begin(); NeighborhoodMap::iterator it; for(; global_neighborhood_it != global_neighborhoods.end(); ++global_neighborhood_it) { it = neighborhoods.find(*global_neighborhood_it); if (it != neighborhoods.end()) it->second->onElementsRemoved(element_list, new_numbering, event); else dummy_synchronizers[*global_neighborhood_it]->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::onElementsAdded(__attribute__((unused)) const Array & element_list, __attribute__((unused)) const NewElementsEvent & event) { - this->resizeElementTypeMap(1, volumes); - this->resizeElementTypeMap(spatial_dimension, quad_positions); + this->resizeElementTypeMap(1, volumes, model.getFEEngine()); + this->resizeElementTypeMap(spatial_dimension, quad_positions, model.getFEEngine()); } /* -------------------------------------------------------------------------- */ void NonLocalManager::resizeElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, - const ElementKind el_kind) { + const FEEngine & fee, const ElementKind el_kind) { Mesh & mesh = this->model.getMesh(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, el_kind); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, el_kind); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, gt); + UInt nb_quads = fee.getNbIntegrationPoints(*it, gt); if(!element_map.exists(*it, gt)) - element_map.alloc(nb_element, nb_component, *it, gt); + element_map.alloc(nb_element * nb_quads, nb_component, *it, gt); else - element_map(*it, gt).resize(nb_element); + element_map(*it, gt).resize(nb_element * nb_quads); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::removeIntegrationPointsFromMap(const ElementTypeMapArray & new_numbering, UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; ElementTypeMapArray::type_iterator it = new_numbering.firstType(_all_dimensions, gt, el_kind); ElementTypeMapArray::type_iterator end = new_numbering.lastType(_all_dimensions, gt, el_kind); for (; it != end; ++it) { ElementType type = *it; if(element_map.exists(type, gt)){ const Array & renumbering = new_numbering(type, gt); Array & vect = element_map(type, gt); UInt nb_quad_per_elem = fee.getNbIntegrationPoints(type, gt); Array tmp(renumbering.getSize()*nb_quad_per_elem, nb_component); AKANTU_DEBUG_ASSERT(tmp.getSize() == vect.getSize(), "Something strange append some mater was created from nowhere!!"); AKANTU_DEBUG_ASSERT(tmp.getSize() == vect.getSize(), "Something strange append some mater was created or disappeared in "<< vect.getID() << "("<< vect.getSize() <<"!=" << tmp.getSize() <<") ""!!"); UInt new_size = 0; for (UInt i = 0; i < renumbering.getSize(); ++i) { UInt new_i = renumbering(i); if(new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component * nb_quad_per_elem, vect.storage() + i * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem * sizeof(Real)); ++new_size; } } tmp.resize(new_size * nb_quad_per_elem); vect.copy(tmp); } } } } __END_AKANTU__ diff --git a/src/model/common/non_local_toolbox/non_local_manager.hh b/src/model/common/non_local_toolbox/non_local_manager.hh index 28ba5ba84..c58d89b01 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.hh +++ b/src/model/common/non_local_toolbox/non_local_manager.hh @@ -1,254 +1,277 @@ /** * @file non_local_manager.hh * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Mon Sep 21 14:21:33 2015 * * @brief Classes that manages all the non-local neighborhoods * * @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 . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_MANAGER_HH__ #define __AKANTU_NON_LOCAL_MANAGER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "solid_mechanics_model.hh" #include "non_local_neighborhood_base.hh" +#include "mesh_events.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ -class NonLocalManager : public Memory, - public Parsable, - public MeshEventHandler { +class NonLocalManager : public Memory, + public Parsable, + public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - NonLocalManager(SolidMechanicsModel & model, - const ID & id = "non_local_manager", - const MemoryID & memory_id = 0); + NonLocalManager(SolidMechanicsModel & model, + const ID & id = "non_local_manager", + const MemoryID & memory_id = 0); virtual ~NonLocalManager(); typedef std::map NeighborhoodMap; typedef std::pair KeyCOO; - -/* -------------------------------------------------------------------------- */ -/* Methods */ -/* -------------------------------------------------------------------------- */ + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ----------------------------------------------------------------------- */ public: - - /// initialize the non-local manager: compute pair lists and weights for all neighborhoods + /// initialize the non-local manager: compute pair lists and weights for all + /// neighborhoods virtual void init(); /// insert new quadrature point in the grid - inline void insertQuad(const IntegrationPoint & quad, const Vector & coords, const ID & neighborhood); + inline void insertQuad(const IntegrationPoint & quad, + const Vector & coords, const ID & neighborhood); /// register non-local neighborhood - inline void registerNeighborhood(const ID & neighborhood, const ID & weight_func_id); + inline void registerNeighborhood(const ID & neighborhood, + const ID & weight_func_id); /// associate a non-local variable to a neighborhood void nonLocalVariableToNeighborhood(const ID & id, const ID & neighborhood); /// return the fem object associated with a provided name inline NonLocalNeighborhoodBase & getNeighborhood(const ID & name) const; /// create the grid synchronizers for each neighborhood void createNeighborhoodSynchronizers(); /// compute the weights in each neighborhood for non-local averaging inline void computeWeights(); /// compute the weights in each neighborhood for non-local averaging inline void updatePairLists(); /// register a new non-local material inline void registerNonLocalMaterial(Material & new_mat); /// register a non-local variable - inline void registerNonLocalVariable(const ID & variable_name, const ID & nl_variable_name, UInt nb_component); + inline void registerNonLocalVariable(const ID & variable_name, + const ID & nl_variable_name, + UInt nb_component); /// average the non-local variables void averageInternals(const GhostType & ghost_type = _not_ghost); - /// average the internals and compute the non-local stresses + /// average the internals and compute the non-local stresses virtual void computeAllNonLocalStresses(); /// register a new internal needed for the weight computations - inline ElementTypeMapReal & registerWeightFunctionInternal(const ID & field_name); + inline ElementTypeMapReal & + registerWeightFunctionInternal(const ID & field_name); /// update the flattened version of the weight function internals inline void updateWeightFunctionInternals(); /// get Nb data for synchronization in parallel - inline UInt getNbDataForElements(const Array & elements, const ID & id) const; + inline UInt getNbDataForElements(const Array & elements, + const ID & id) const; /// pack data for synchronization in parallel - inline void packElementData(CommunicationBuffer & buffer, const Array & elements, - SynchronizationTag tag, const ID & id) const; + inline void packElementData(CommunicationBuffer & buffer, + const Array & elements, + SynchronizationTag tag, const ID & id) const; /// unpack data for synchronization in parallel - inline void unpackElementData(CommunicationBuffer & buffer, const Array & elements, - SynchronizationTag tag, const ID & id) const; - -/* -------------------------------------------------------------------------- */ -/* MeshEventHandler inherited members */ -/* -------------------------------------------------------------------------- */ + inline void unpackElementData(CommunicationBuffer & buffer, + const Array & elements, + SynchronizationTag tag, const ID & id) const; - virtual void onElementsRemoved(const Array & element_list, - const ElementTypeMapArray & new_numbering, - const RemovedElementsEvent & event); - - virtual void onElementsAdded(const Array & element_list, - const NewElementsEvent & event); protected: - /// create a new neighborhood for a given domain ID void createNeighborhood(const ID & weight_func, const ID & neighborhood); /// flatten the material internal fields needed for the non-local computations void flattenInternal(ElementTypeMapReal & internal_flat, - const GhostType & ghost_type, - const ElementKind & kind); + const GhostType & ghost_type, const ElementKind & kind); /// set the values of the jacobians void setJacobians(const FEEngine & fe_engine, const ElementKind & kind); /// allocation of eelment type maps - void initElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, - const FEEngine & fe_engine, const ElementKind el_kind = _ek_regular); + void initElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, + const FEEngine & fe_engine, + const ElementKind el_kind = _ek_regular); /// resizing of element type maps void resizeElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, - const ElementKind el_kind = _ek_regular); + const FEEngine & fee, + const ElementKind el_kind = _ek_regular); /// remove integration points from element type maps - void removeIntegrationPointsFromMap(const ElementTypeMapArray & new_numbering, UInt nb_component, - ElementTypeMapReal & element_map, const FEEngine & fee, - const ElementKind el_kind = _ek_regular); - + void removeIntegrationPointsFromMap( + const ElementTypeMapArray & new_numbering, UInt nb_component, + ElementTypeMapReal & element_map, const FEEngine & fee, + const ElementKind el_kind = _ek_regular); + /// allocate the non-local variables void initNonLocalVariables(); /// copy the results of the averaging in the materials void distributeInternals(ElementKind kind); /// cleanup unneccessary ghosts void cleanupExtraGhostElements(ElementTypeMap & nb_ghost_protected); /* ------------------------------------------------------------------------ */ - /* Accessors */ + /* MeshEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: + virtual void onElementsRemoved(const Array & element_list, + const ElementTypeMapArray & new_numbering, + const RemovedElementsEvent & event); + + virtual void onElementsAdded(const Array & element_list, + const NewElementsEvent & event); + + virtual void onElementsChanged(__attribute__((unused)) const Array & old_elements_list, + __attribute__((unused)) const Array & new_elements_list, + __attribute__((unused)) const ElementTypeMapArray & new_numbering, + __attribute__((unused)) const ChangedElementsEvent & event) {}; + + virtual void onNodesAdded(__attribute__((unused)) const Array & nodes_list, + __attribute__((unused)) const NewNodesEvent & event) {}; + virtual void onNodesRemoved(__attribute__((unused)) const Array & nodes_list, + __attribute__((unused)) const Array & new_numbering, + __attribute__((unused)) const RemovedNodesEvent & event) {}; + /* ------------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------------ */ +public: AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); AKANTU_GET_MACRO(Model, model, const SolidMechanicsModel &); AKANTU_GET_MACRO_NOT_CONST(Volumes, volumes, ElementTypeMapReal &) AKANTU_GET_MACRO(NbStressCalls, compute_stress_calls, UInt); - inline const Array & getJacobians(const ElementType & type, const GhostType & ghost_type) { + inline const Array & getJacobians(const ElementType & type, + const GhostType & ghost_type) { return *jacobians(type, ghost_type); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: - /// the non-local neighborhoods present NeighborhoodMap neighborhoods; /// list of all the non-local materials in the model - std::vector non_local_materials; + std::vector non_local_materials; struct NonLocalVariable { - NonLocalVariable(const ID & variable_name, const ID & nl_variable_name, const ID & id, UInt nb_component) : - local(variable_name, id), - non_local(nl_variable_name, id), - nb_component(nb_component){ - } + NonLocalVariable(const ID & variable_name, const ID & nl_variable_name, + const ID & id, UInt nb_component) + : local(variable_name, id), non_local(nl_variable_name, id), + nb_component(nb_component) {} ElementTypeMapReal local; ElementTypeMapReal non_local; UInt nb_component; }; /// the non-local variables associated to a certain neighborhood std::map non_local_variables; /// reference to the model SolidMechanicsModel & model; /// jacobians for all the elements in the mesh - ElementTypeMap * > jacobians; + ElementTypeMap *> jacobians; /// store the position of the quadrature points ElementTypeMapReal quad_positions; - /// store the volume of each quadrature point for the non-local weight normalization - ElementTypeMapReal volumes; + /// store the volume of each quadrature point for the non-local weight + /// normalization + ElementTypeMapReal volumes; /// the spatial dimension const UInt spatial_dimension; /// counter for computeStress calls UInt compute_stress_calls; /// map to store weight function types from input file std::map weight_function_types; /// map to store the internals needed by the weight functions std::map weight_function_internals; -/* -------------------------------------------------------------------------- */ - /// the following are members needed to make this processor participate in the grid creation of neighborhoods he doesn't own as a member. For details see createGridSynchronizers function + /* -------------------------------------------------------------------------- + */ + /// the following are members needed to make this processor participate in the + /// grid creation of neighborhoods he doesn't own as a member. For details see + /// createGridSynchronizers function /// synchronizer registry for dummy grid synchronizers SynchronizerRegistry * dummy_registry; /// map of dummy synchronizers std::map dummy_synchronizers; /// dummy spatial grid SpatialGrid * dummy_grid; /// create a set of all neighborhoods present in the simulation std::set global_neighborhoods; class DummyDataAccessor : public DataAccessor { public: - virtual inline UInt getNbDataForElements(){return 0;}; + virtual inline UInt getNbDataForElements() { return 0; }; virtual inline void packElementData(){}; virtual inline void unpackElementData(){}; }; DummyDataAccessor dummy_accessor; }; __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "non_local_manager_inline_impl.cc" - #endif /* __AKANTU_NON_LOCAL_MANAGER_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc b/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc index 7e6380436..11797e49f 100644 --- a/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc +++ b/src/model/common/non_local_toolbox/non_local_manager_inline_impl.cc @@ -1,233 +1,234 @@ /** * @file non_local_manager_inline_impl.cc * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Mon Sep 21 17:30:03 2015 * * @brief inline implementation of non-local manager functions * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "grid_synchronizer.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_MANAGER_INLINE_IMPL_CC__ #define __AKANTU_NON_LOCAL_MANAGER_INLINE_IMPL_CC__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ inline void NonLocalManager::insertQuad(const IntegrationPoint & quad, const Vector & coords, const ID & neighborhood) { AKANTU_DEBUG_ASSERT(neighborhoods[neighborhood] != NULL, "The neighborhood " << neighborhood << "has not been created"); neighborhoods[neighborhood]->insertQuad(quad, coords); } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::registerNeighborhood(const ID & neighborhood, const ID & weight_func_id) { /// check if neighborhood has already been created NeighborhoodMap::const_iterator it = neighborhoods.find(neighborhood); if (it == neighborhoods.end()) { this->createNeighborhood(weight_func_id, neighborhood); } } /* -------------------------------------------------------------------------- */ inline NonLocalNeighborhoodBase & NonLocalManager::getNeighborhood(const ID & name) const{ AKANTU_DEBUG_IN(); NeighborhoodMap::const_iterator it = neighborhoods.find(name); AKANTU_DEBUG_ASSERT(it != neighborhoods.end(), "The neighborhood " << name << " is not registered"); AKANTU_DEBUG_OUT(); return *(it->second); } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::computeWeights() { AKANTU_DEBUG_IN(); this->updateWeightFunctionInternals(); this->volumes.clear(); // NeighborhoodMap::iterator it = neighborhoods.begin(); // NeighborhoodMap::iterator end = neighborhoods.end(); // for (; it != end; ++it) // it->second->updateWeights(); /// loop over all the neighborhoods and call onElementsRemoved std::set::const_iterator global_neighborhood_it = global_neighborhoods.begin(); NeighborhoodMap::iterator it; for(; global_neighborhood_it != global_neighborhoods.end(); ++global_neighborhood_it) { it = neighborhoods.find(*global_neighborhood_it); if (it != neighborhoods.end()) it->second->updateWeights(); else { dummy_synchronizers[*global_neighborhood_it]->asynchronousSynchronize(dummy_accessor, _gst_mnl_weight); dummy_synchronizers[*global_neighborhood_it]->waitEndSynchronize(dummy_accessor, _gst_mnl_weight); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::updatePairLists() { AKANTU_DEBUG_IN(); /// compute the position of the quadrature points this->model.getFEEngine().computeIntegrationPointsCoordinates(quad_positions); NeighborhoodMap::iterator it = neighborhoods.begin(); NeighborhoodMap::iterator end = neighborhoods.end(); for (; it != end; ++it) it->second->updatePairList(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::registerNonLocalVariable(const ID & variable_name, const ID & nl_variable_name, UInt nb_component) { AKANTU_DEBUG_IN(); std::map::iterator non_local_variable_it = non_local_variables.find(variable_name); if (non_local_variable_it == non_local_variables.end()) non_local_variables[nl_variable_name] = new NonLocalVariable(variable_name, nl_variable_name, this->id, nb_component); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::registerNonLocalMaterial(Material & new_mat) { non_local_materials.push_back(&new_mat); } /* -------------------------------------------------------------------------- */ inline ElementTypeMapReal & NonLocalManager::registerWeightFunctionInternal(const ID & field_name) { AKANTU_DEBUG_IN(); std::map::const_iterator it = this->weight_function_internals.find(field_name); if (it == weight_function_internals.end()) { weight_function_internals[field_name] = new ElementTypeMapReal(field_name, id); } return *(weight_function_internals[field_name]); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::updateWeightFunctionInternals() { std::map::const_iterator it = this->weight_function_internals.begin(); std::map::const_iterator end = this->weight_function_internals.end(); for (; it != end; ++it) { it->second->clear(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType ghost_type = (GhostType) g; this->flattenInternal(*(it->second), ghost_type, _ek_regular); } } } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::nonLocalVariableToNeighborhood(const ID & variable_name, const ID & neighborhood) { NeighborhoodMap::const_iterator it = neighborhoods.find(neighborhood); AKANTU_DEBUG_ASSERT(it != neighborhoods.end(), "The neighborhood " << neighborhood << " is not registered"); it->second->registerNonLocalVariable(variable_name); } /* -------------------------------------------------------------------------- */ inline UInt NonLocalManager::getNbDataForElements(const Array & elements, const ID & id) const { UInt size = 0; UInt nb_quadrature_points = this->getModel().getNbIntegrationPoints(elements); std::map::const_iterator it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); size += it->second->nb_component * sizeof(Real) * nb_quadrature_points; return size; } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag, const ID & id) const { std::map::const_iterator it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor::packElementalDataHelper(it->second->local, buffer, elements, true, this->model.getFEEngine()); } /* -------------------------------------------------------------------------- */ inline void NonLocalManager::unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag, const ID & id) const { std::map::const_iterator it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor::unpackElementalDataHelper(it->second->local, buffer, elements, true, this->model.getFEEngine()); } __END_AKANTU__ #endif /* __AKANTU_NON_LOCAL_MANAGER_INLINE_IMPL_CC__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood.hh b/src/model/common/non_local_toolbox/non_local_neighborhood.hh index 49806f3bf..3ccb7dcc1 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood.hh @@ -1,131 +1,132 @@ /** * @file non_local_neighborhood.hh * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Sat Sep 26 18:29:59 2015 * * @brief Non-local neighborhood for non-local averaging based on * weight function * * @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 . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_HH__ /* -------------------------------------------------------------------------- */ #include "base_weight_function.hh" #include "non_local_neighborhood_base.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class NonLocalManager; class TestWeightFunction; } __BEGIN_AKANTU__ template class NonLocalNeighborhood : public NonLocalNeighborhoodBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLocalNeighborhood(NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates, const ID & id = "neighborhood", const MemoryID & memory_id = 0); virtual ~NonLocalNeighborhood(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// compute the weights for non-local averaging void computeWeights(); /// save the pair of weights in a file void saveWeights(const std::string & filename) const; /// compute the non-local counter part for a given element type map virtual void weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const; /// update the weights based on the weight function void updateWeights(); /// register a new non-local variable in the neighborhood virtual void registerNonLocalVariable(const ID & id); protected: virtual inline UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const; virtual inline void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const; virtual inline void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag); /* -------------------------------------------------------------------------- */ /* Accessor */ /* -------------------------------------------------------------------------- */ AKANTU_GET_MACRO(NonLocalManager, *non_local_manager, const NonLocalManager &); AKANTU_GET_MACRO_NOT_CONST(NonLocalManager, *non_local_manager, NonLocalManager &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// Pointer to non-local manager class NonLocalManager * non_local_manager; /// the weights associated to the pairs Array * pair_weight[2]; /// weight function WeightFunction * weight_function; }; __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* Implementation of template functions */ /* -------------------------------------------------------------------------- */ #include "non_local_neighborhood_tmpl.hh" /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "non_local_neighborhood_inline_impl.cc" #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc b/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc index c9deee166..b3bb7d761 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc @@ -1,109 +1,110 @@ /** * @file non_local_neighborhood_base.cc * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Mon Sep 21 18:10:49 2015 * * @brief Implementation of non-local neighborhood base * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "non_local_neighborhood_base.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ NonLocalNeighborhoodBase::NonLocalNeighborhoodBase(const SolidMechanicsModel & model, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : NeighborhoodBase(model, quad_coordinates, id, memory_id), Parsable(_st_non_local, id) { AKANTU_DEBUG_IN(); this->registerParam("radius" , neighborhood_radius , 100., _pat_parsable | _pat_readable , "Non local radius"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NonLocalNeighborhoodBase::~NonLocalNeighborhoodBase() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::createGridSynchronizer() { this->is_creating_grid = true; std::set tags; tags.insert(_gst_mnl_for_average); tags.insert(_gst_mnl_weight); std::stringstream sstr; sstr << getID() << ":grid_synchronizer"; this->grid_synchronizer = GridSynchronizer::createGridSynchronizer(this->model.getMesh(), *spatial_grid, sstr.str(), synch_registry, tags, 0, false); this->is_creating_grid = false; } /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::cleanupExtraGhostElements(std::set & 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 ghosts_to_erase(0); Mesh & mesh = this->model.getMesh(); 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; std::set::const_iterator end = relevant_ghost_elements.end(); for(; it != last_type; ++it) { element.type = *it; UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); for (UInt g = 0; g < nb_ghost_elem; ++g) { element.element = g; if (relevant_ghost_elements.find(element) == end) { ghosts_to_erase.push_back(element); } } } /// remove the unneccessary ghosts from the synchronizer this->grid_synchronizer->removeElements(ghosts_to_erase); } __END_AKANTU__ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh index 7c591842d..9d104308d 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh @@ -1,121 +1,122 @@ /** * @file non_local_neighborhood_base.hh * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Mon Sep 21 15:43:26 2015 * * @brief Non-local neighborhood base class * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class NonLocalNeighborhoodBase : public NeighborhoodBase, public Parsable{ /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLocalNeighborhoodBase(const SolidMechanicsModel & model, const ElementTypeMapReal & quad_coordinates, const ID & id = "non_local_neighborhood", const MemoryID & memory_id = 0); virtual ~NonLocalNeighborhoodBase(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// create grid synchronizer and exchange ghost cells virtual void createGridSynchronizer(); /// compute weights, for instance needed for non-local damage computation virtual void computeWeights() {}; /// compute the non-local counter part for a given element type map virtual void weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const {}; /// update the weights for the non-local averaging virtual void updateWeights() {}; /// register a new non-local variable in the neighborhood virtual void registerNonLocalVariable(const ID & id) {}; /// clean up the unneccessary ghosts void cleanupExtraGhostElements(std::set & relevant_ghost_elements); protected: /// create the grid void createGrid(); /* -------------------------------------------------------------------------- */ /* DataAccessor inherited members */ /* -------------------------------------------------------------------------- */ public: virtual inline UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const {return 0; }; virtual inline void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const {}; virtual inline void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) {}; /* -------------------------------------------------------------------------- */ /* Accessors */ /* -------------------------------------------------------------------------- */ public: AKANTU_GET_MACRO(NonLocalVariables, non_local_variables, const std::set &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of non-local variables associated to the neighborhood std::set non_local_variables; }; __END_AKANTU__ #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc b/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc index 3414af0e7..77b5640e3 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_inline_impl.cc @@ -1,91 +1,92 @@ /** * @file non_local_neighborhood_inline_impl.cc * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Mon Oct 5 09:36:33 2015 * * @brief Implementation of inline functions of non-local neighborhood class * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_INLINE_IMPL_CC__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_INLINE_IMPL_CC__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template inline UInt NonLocalNeighborhood::getNbDataForElements(const Array & elements, SynchronizationTag tag) const { UInt size = 0; if(tag == _gst_mnl_for_average) { std::set::const_iterator it = non_local_variables.begin(); std::set::const_iterator end = non_local_variables.end(); for(;it != end; ++it) { size += this->non_local_manager->getNbDataForElements(elements, *it); } } size += this->weight_function->getNbDataForElements(elements, tag); return size; } /* -------------------------------------------------------------------------- */ template inline void NonLocalNeighborhood::packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const { if(tag == _gst_mnl_for_average) { std::set::const_iterator it = non_local_variables.begin(); std::set::const_iterator end = non_local_variables.end(); for(;it != end; ++it) { this->non_local_manager->packElementData(buffer, elements, tag, *it); } } this->weight_function->packElementData(buffer, elements, tag); } /* -------------------------------------------------------------------------- */ template inline void NonLocalNeighborhood::unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) { if(tag == _gst_mnl_for_average) { std::set::const_iterator it = non_local_variables.begin(); std::set::const_iterator end = non_local_variables.end(); for(;it != end; ++it) { this->non_local_manager->unpackElementData(buffer, elements, tag, *it); } } this->weight_function->unpackElementData(buffer, elements, tag); } __END_AKANTU__ #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_INLINE_IMPL_CC__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh index ba4417382..794755440 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,282 +1,283 @@ /** * @file non_local_neighborhood_tmpl.hh * @author Aurelia Isabel Cuba Ramos + * @author Nicolas Richart * @date Sat Sep 26 18:43:30 2015 * * @brief Implementation of class non-local neighborhood * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "non_local_manager.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template NonLocalNeighborhood::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(); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; pair_weight[ghost_type] = NULL; } this->weight_function = new WeightFunction(this->getNonLocalManager()); this->registerSubSection(_st_weight_function, "weight_parameter", *weight_function); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template NonLocalNeighborhood::~NonLocalNeighborhood() { AKANTU_DEBUG_IN(); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; delete pair_weight[ghost_type]; } delete weight_function; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::computeWeights() { AKANTU_DEBUG_IN(); this->weight_function->setRadius(this->neighborhood_radius); Vector q1_coord(this->spatial_dimension); Vector 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(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; /// allocate the array to store the weight, if it doesn't exist already if(!(pair_weight[ghost_type])) { std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; std::stringstream sstr; sstr << this->id <<":pair_weight:" << ghost_id; pair_weight[ghost_type] = new Array(0, nb_weights_per_pair, sstr.str()); } /// resize the array to the correct size pair_weight[ghost_type]->resize(pair_list[ghost_type].size()); /// set entries to zero pair_weight[ghost_type]->clear(); /// loop over all pairs in the current pair list array and their corresponding weights PairList::const_iterator first_pair = pair_list[ghost_type].begin(); PairList::const_iterator last_pair = pair_list[ghost_type].end(); Array::vector_iterator weight_it = pair_weight[ghost_type]->begin(nb_weights_per_pair); // Compute the weights for(;first_pair != last_pair; ++first_pair, ++weight_it) { Vector & 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::const_vector_iterator coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type).begin(this->spatial_dimension); q1_coord = coords_type_1_it[q1.global_num]; Array::const_vector_iterator coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type).begin(this->spatial_dimension); q2_coord = coords_type_2_it[q2.global_num]; Array & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); const Array & 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 & jacobians_1 = this->non_local_manager->getJacobians(q1.type, q1.ghost_type); Array & 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(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); Array::vector_iterator weight_it = pair_weight[ghost_type2]->begin(nb_weights_per_pair); // Compute the weights for(;first_pair != last_pair; ++first_pair, ++weight_it) { Vector & weight = *weight_it; const IntegrationPoint & q1 = first_pair->first; const IntegrationPoint & q2 = first_pair->second; Array & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); Array & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); Real q1_volume = quad_volumes_1(q1.global_num); 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 void NonLocalNeighborhood::saveWeights(const std::string & filename) const { std::ofstream pout; std::stringstream sstr; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; AKANTU_DEBUG_ASSERT((pair_weight[ghost_type]), "the weights have not been computed yet"); Array & weights = *(pair_weight[ghost_type]); Array::const_vector_iterator weights_it = weights.begin(2); for (UInt i = 0; i < weights.getSize(); ++i, ++weights_it) pout << "w1: " << (*weights_it)(0) <<" w2: " << (*weights_it)(1) << std::endl; } } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const { AKANTU_DEBUG_IN(); std::set::iterator it = non_local_variables.find(accumulated.getName()); ///do averaging only for variables registered in the neighborhood if (it != non_local_variables.end()) { PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); Array::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); // Compute the weights for(;first_pair != last_pair; ++first_pair, ++weight_it) { Vector & weight = *weight_it; const IntegrationPoint & q1 = first_pair->first; const IntegrationPoint & q2 = first_pair->second; const Array & to_acc_1 = to_accumulate(q1.type, q1.ghost_type); Array & acc_1 = accumulated(q1.type, q1.ghost_type); const Array & to_acc_2 = to_accumulate(q2.type, q2.ghost_type); Array & acc_2 = accumulated(q2.type, q2.ghost_type); for(UInt d = 0; d < nb_degree_of_freedom; ++d) { acc_1(q1.global_num, d) += weight(0) * to_acc_2(q2.global_num, d); } if(ghost_type2 != _ghost) { for(UInt d = 0; d < nb_degree_of_freedom; ++d) { acc_2(q2.global_num, d) += weight(1) * to_acc_1(q1.global_num, d); } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::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)) { this->synch_registry->asynchronousSynchronize(_gst_mnl_weight); this->synch_registry->waitEndSynchronize(_gst_mnl_weight); this->computeWeights(); } } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::registerNonLocalVariable(const ID & id) { this->non_local_variables.insert(id); } __END_AKANTU__ #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL__ */ diff --git a/src/model/heat_transfer/heat_transfer_model.cc b/src/model/heat_transfer/heat_transfer_model.cc index 63acd8ac5..3eb41bb3d 100644 --- a/src/model/heat_transfer/heat_transfer_model.cc +++ b/src/model/heat_transfer/heat_transfer_model.cc @@ -1,1251 +1,1255 @@ /** * @file heat_transfer_model.cc * * @author Guillaume Anciaux * @author Lucas Frerot * @author Srinivasa Babu Ramisetti * @author David Simon Kammer * @author Nicolas Richart * @author Rui Wang * * @date creation: Sun May 01 2011 * @date last modification: Mon Sep 15 2014 * * @brief Implementation of HeatTransferModel class * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "heat_transfer_model.hh" #include "group_manager_inline_impl.cc" #include "dumpable_inline_impl.hh" #include "aka_math.hh" #include "aka_common.hh" #include "fe_engine_template.hh" #include "mesh.hh" #include "static_communicator.hh" #include "parser.hh" #include "generalized_trapezoidal.hh" #ifdef AKANTU_USE_MUMPS #include "solver_mumps.hh" #endif #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" # include "dumper_elemental_field.hh" # include "dumper_element_partition.hh" # include "dumper_internal_material_field.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const HeatTransferModelOptions default_heat_transfer_model_options(_explicit_lumped_capacity); /* -------------------------------------------------------------------------- */ HeatTransferModel::HeatTransferModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), Parsable(_st_heat, id), integrator(NULL), conductivity_matrix(NULL), capacity_matrix(NULL), jacobian_matrix(NULL), temperature_gradient ("temperature_gradient", id), temperature_on_qpoints ("temperature_on_qpoints", id), conductivity_on_qpoints ("conductivity_on_qpoints", id), k_gradt_on_qpoints ("k_gradt_on_qpoints", id), int_bt_k_gT ("int_bt_k_gT", id), bt_k_gT ("bt_k_gT", id), conductivity(spatial_dimension, spatial_dimension), thermal_energy ("thermal_energy", id), - solver(NULL) { + solver(NULL), + pbc_synch(NULL) { AKANTU_DEBUG_IN(); createSynchronizerRegistry(this); std::stringstream sstr; sstr << id << ":fem"; registerFEEngineObject(sstr.str(), mesh,spatial_dimension); this->temperature= NULL; this->residual = NULL; this->blocked_dofs = NULL; #ifdef AKANTU_USE_IOHELPER this->mesh.registerDumper("paraview_all", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular); #endif this->registerParam("conductivity" , conductivity , _pat_parsmod); this->registerParam("conductivity_variation", conductivity_variation, 0., _pat_parsmod); this->registerParam("temperature_reference" , T_ref , 0., _pat_parsmod); this->registerParam("capacity" , capacity , _pat_parsmod); this->registerParam("density" , density , _pat_parsmod); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initModel() { getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initParallel(MeshPartition * partition, DataAccessor * data_accessor) { AKANTU_DEBUG_IN(); if (data_accessor == NULL) data_accessor = this; Synchronizer & synch_parallel = createParallelSynch(partition,data_accessor); synch_registry->registerSynchronizer(synch_parallel, _gst_htm_capacity); synch_registry->registerSynchronizer(synch_parallel, _gst_htm_temperature); synch_registry->registerSynchronizer(synch_parallel, _gst_htm_gradient_temperature); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initPBC() { AKANTU_DEBUG_IN(); Model::initPBC(); - PBCSynchronizer * synch = new PBCSynchronizer(pbc_pair); + pbc_synch = new PBCSynchronizer(pbc_pair); - synch_registry->registerSynchronizer(*synch, _gst_htm_capacity); - synch_registry->registerSynchronizer(*synch, _gst_htm_temperature); + synch_registry->registerSynchronizer(*pbc_synch, _gst_htm_capacity); + synch_registry->registerSynchronizer(*pbc_synch, _gst_htm_temperature); changeLocalEquationNumberForPBC(pbc_pair,1); // as long as there are ones on the diagonal of the matrix, we can put boudandary true for slaves std::map::iterator it = pbc_pair.begin(); std::map::iterator end = pbc_pair.end(); while(it != end) { (*blocked_dofs)((*it).first,0) = true; ++it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initArrays() { AKANTU_DEBUG_IN(); UInt nb_nodes = getFEEngine().getMesh().getNbNodes(); std::stringstream sstr_temp; sstr_temp << Model::id << ":temperature"; std::stringstream sstr_temp_rate; sstr_temp_rate << Model::id << ":temperature_rate"; std::stringstream sstr_inc; sstr_inc << Model::id << ":increment"; std::stringstream sstr_ext_flx; sstr_ext_flx << Model::id << ":external_flux"; std::stringstream sstr_residual; sstr_residual << Model::id << ":residual"; std::stringstream sstr_lump; sstr_lump << Model::id << ":lumped"; std::stringstream sstr_boun; sstr_boun << Model::id << ":blocked_dofs"; temperature = &(alloc(sstr_temp.str(), nb_nodes, 1, REAL_INIT_VALUE)); temperature_rate = &(alloc(sstr_temp_rate.str(), nb_nodes, 1, REAL_INIT_VALUE)); increment = &(alloc(sstr_inc.str(), nb_nodes, 1, REAL_INIT_VALUE)); external_heat_rate = &(alloc(sstr_ext_flx.str(), nb_nodes, 1, REAL_INIT_VALUE)); residual = &(alloc(sstr_residual.str(), nb_nodes, 1, REAL_INIT_VALUE)); capacity_lumped = &(alloc(sstr_lump.str(), nb_nodes, 1, REAL_INIT_VALUE)); blocked_dofs = &(alloc(sstr_boun.str(), nb_nodes, 1, false)); Mesh::ConnectivityTypeList::const_iterator it; /* -------------------------------------------------------------------------- */ // byelementtype vectors getFEEngine().getMesh().initElementTypeMapArray(temperature_on_qpoints, 1, spatial_dimension); getFEEngine().getMesh().initElementTypeMapArray(temperature_gradient, spatial_dimension, spatial_dimension); getFEEngine().getMesh().initElementTypeMapArray(conductivity_on_qpoints, spatial_dimension*spatial_dimension, spatial_dimension); getFEEngine().getMesh().initElementTypeMapArray(k_gradt_on_qpoints, spatial_dimension, spatial_dimension); getFEEngine().getMesh().initElementTypeMapArray(bt_k_gT, 1, spatial_dimension, true); getFEEngine().getMesh().initElementTypeMapArray(int_bt_k_gT, 1, spatial_dimension, true); getFEEngine().getMesh().initElementTypeMapArray(thermal_energy, 1, spatial_dimension); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; const Mesh::ConnectivityTypeList & type_list = getFEEngine().getMesh().getConnectivityTypeList(gt); for(it = type_list.begin(); it != type_list.end(); ++it) { if(Mesh::getSpatialDimension(*it) != spatial_dimension) continue; UInt nb_element = getFEEngine().getMesh().getNbElement(*it, gt); UInt nb_quad_points = this->getFEEngine().getNbIntegrationPoints(*it, gt) * nb_element; temperature_on_qpoints(*it, gt).resize(nb_quad_points); temperature_on_qpoints(*it, gt).clear(); temperature_gradient(*it, gt).resize(nb_quad_points); temperature_gradient(*it, gt).clear(); conductivity_on_qpoints(*it, gt).resize(nb_quad_points); conductivity_on_qpoints(*it, gt).clear(); k_gradt_on_qpoints(*it, gt).resize(nb_quad_points); k_gradt_on_qpoints(*it, gt).clear(); bt_k_gT(*it, gt).resize(nb_quad_points); bt_k_gT(*it, gt).clear(); int_bt_k_gT(*it, gt).resize(nb_element); int_bt_k_gT(*it, gt).clear(); thermal_energy(*it, gt).resize(nb_element); thermal_energy(*it, gt).clear(); } } /* -------------------------------------------------------------------------- */ dof_synchronizer = new DOFSynchronizer(getFEEngine().getMesh(),1); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initSolver(__attribute__((unused)) SolverOptions & options) { #if !defined(AKANTU_USE_MUMPS) // or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake AKANTU_DEBUG_ERROR("You should at least activate one solver."); #else UInt nb_global_nodes = mesh.getNbGlobalNodes(); delete jacobian_matrix; std::stringstream sstr; sstr << Memory::id << ":jacobian_matrix"; jacobian_matrix = new SparseMatrix(nb_global_nodes, _symmetric, sstr.str(), memory_id); jacobian_matrix->buildProfile(mesh, *dof_synchronizer, 1); delete conductivity_matrix; std::stringstream sstr_sti; sstr_sti << Memory::id << ":conductivity_matrix"; conductivity_matrix = new SparseMatrix(*jacobian_matrix, sstr_sti.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solv; sstr_solv << Memory::id << ":solver"; solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS if(solver) solver->initialize(options); #endif //AKANTU_HAS_SOLVER } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); method = dynamic ? _implicit_dynamic : _static; initSolver(solver_options); if(method == _implicit_dynamic) { if(integrator) delete integrator; integrator = new TrapezoidalRule1(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ HeatTransferModel::~HeatTransferModel() { AKANTU_DEBUG_IN(); if (integrator) delete integrator ; if (conductivity_matrix) delete conductivity_matrix; if (capacity_matrix) delete capacity_matrix ; if (jacobian_matrix) delete jacobian_matrix ; if (solver) delete solver ; + + delete pbc_synch; + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleCapacityLumped(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); FEEngine & fem = getFEEngine(); const Mesh::ConnectivityTypeList & type_list = fem.getMesh().getConnectivityTypeList(ghost_type); Mesh::ConnectivityTypeList::const_iterator it; for(it = type_list.begin(); it != type_list.end(); ++it) { if(Mesh::getSpatialDimension(*it) != spatial_dimension) continue; UInt nb_element = getFEEngine().getMesh().getNbElement(*it,ghost_type); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(*it, ghost_type); Array rho_1 (nb_element * nb_quadrature_points,1, capacity * density); fem.assembleFieldLumped(rho_1,1,*capacity_lumped, dof_synchronizer->getLocalDOFEquationNumbers(), *it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleCapacityLumped() { AKANTU_DEBUG_IN(); capacity_lumped->clear(); assembleCapacityLumped(_not_ghost); assembleCapacityLumped(_ghost); getSynchronizerRegistry().synchronize(_gst_htm_capacity); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::updateResidual(bool compute_conductivity) { AKANTU_DEBUG_IN(); /// @f$ r = q_{ext} - q_{int} - C \dot T @f$ // start synchronization synch_registry->asynchronousSynchronize(_gst_htm_temperature); // finalize communications synch_registry->waitEndSynchronize(_gst_htm_temperature); //clear the array /// first @f$ r = q_{ext} @f$ // residual->clear(); residual->copy(*external_heat_rate); /// then @f$ r -= q_{int} @f$ // update the not ghost ones updateResidual(_not_ghost); // update for the received ghosts updateResidual(_ghost); /* if (method == _explicit_lumped_capacity) { this->solveExplicitLumped(); }*/ AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleConductivityMatrix(bool compute_conductivity) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); conductivity_matrix->clear(); switch(mesh.getSpatialDimension()) { case 1: this->assembleConductivityMatrix<1>(_not_ghost,compute_conductivity); break; case 2: this->assembleConductivityMatrix<2>(_not_ghost,compute_conductivity); break; case 3: this->assembleConductivityMatrix<3>(_not_ghost,compute_conductivity); break; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void HeatTransferModel::assembleConductivityMatrix(const GhostType & ghost_type,bool compute_conductivity) { AKANTU_DEBUG_IN(); Mesh & mesh = this->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) { this->assembleConductivityMatrix(*it, ghost_type,compute_conductivity); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template void HeatTransferModel::assembleConductivityMatrix(const ElementType & type, const GhostType & ghost_type, bool compute_conductivity) { AKANTU_DEBUG_IN(); SparseMatrix & K = *conductivity_matrix; const Array & shapes_derivatives = this->getFEEngine().getShapesDerivatives(type, ghost_type); UInt nb_element = mesh.getNbElement(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type, ghost_type); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = nb_nodes_per_element; Array * bt_d_b = new Array(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix Bt_D(nb_nodes_per_element, dim); Array::const_iterator< Matrix > shapes_derivatives_it = shapes_derivatives.begin(dim, nb_nodes_per_element); Array::iterator< Matrix > Bt_D_B_it = bt_d_b->begin(bt_d_b_size, bt_d_b_size); if (compute_conductivity) this->computeConductivityOnQuadPoints(ghost_type); Array::iterator< Matrix > D_it = conductivity_on_qpoints(type, ghost_type).begin(dim, dim); Array::iterator< Matrix > D_end = conductivity_on_qpoints(type, ghost_type).end(dim, dim); for (; D_it != D_end; ++D_it, ++Bt_D_B_it, ++shapes_derivatives_it) { Matrix & D = *D_it; const Matrix & B = *shapes_derivatives_it; Matrix & Bt_D_B = *Bt_D_B_it; Bt_D.mul(B, D); Bt_D_B.mul(Bt_D, B); } /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * K_e = new Array(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); this->getFEEngine().integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type); delete bt_d_b; this->getFEEngine().assembleMatrix(*K_e, K, 1, type, ghost_type); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::updateResidualInternal() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Update the residual"); // f = q_ext - q_int - Mddot = q - Mddot; if(method != _static) { // f -= Mddot if(capacity_matrix) { // if full mass_matrix Array * Mddot = new Array(*temperature_rate, true, "Mddot"); *Mddot *= *capacity_matrix; *residual -= *Mddot; delete Mddot; } else if (capacity_lumped) { // else lumped mass UInt nb_nodes = temperature_rate->getSize(); UInt nb_degree_of_freedom = temperature_rate->getNbComponent(); Real * capacity_val = capacity_lumped->storage(); Real * temp_rate_val = temperature_rate->storage(); Real * res_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *res_val -= *temp_rate_val * *capacity_val; } blocked_dofs_val++; res_val++; capacity_val++; temp_rate_val++; } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::solveStatic() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving Ku = f"); AKANTU_DEBUG_ASSERT(conductivity_matrix != NULL, "You should first initialize the implicit solver and assemble the stiffness matrix"); UInt nb_nodes = temperature->getSize(); UInt nb_degree_of_freedom = temperature->getNbComponent() * nb_nodes; jacobian_matrix->copyContent(*conductivity_matrix); jacobian_matrix->applyBoundary(*blocked_dofs); increment->clear(); solver->setRHS(*residual); solver->factorize(); solver->solve(*increment); Real * increment_val = increment->storage(); Real * temperature_val = temperature->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++temperature_val, ++increment_val, ++blocked_dofs_val) { if (!(*blocked_dofs_val)) { *temperature_val += *increment_val; } else { *increment_val = 0.0; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::computeConductivityOnQuadPoints(const GhostType & ghost_type) { const Mesh::ConnectivityTypeList & type_list = this->getFEEngine().getMesh().getConnectivityTypeList(ghost_type); Mesh::ConnectivityTypeList::const_iterator it; for(it = type_list.begin(); it != type_list.end(); ++it) { if(Mesh::getSpatialDimension(*it) != spatial_dimension) continue; Array & temperature_interpolated = temperature_on_qpoints(*it, ghost_type); //compute the temperature on quadrature points this->getFEEngine().interpolateOnIntegrationPoints(*temperature, temperature_interpolated, 1 ,*it,ghost_type); Array::matrix_iterator C_it = conductivity_on_qpoints(*it, ghost_type).begin(spatial_dimension, spatial_dimension); Array::matrix_iterator C_end = conductivity_on_qpoints(*it, ghost_type).end(spatial_dimension, spatial_dimension); Array::iterator T_it = temperature_interpolated.begin(); for (;C_it != C_end; ++C_it, ++T_it) { Matrix & C = *C_it; Real & T = *T_it; C = conductivity; Matrix variation(spatial_dimension, spatial_dimension, conductivity_variation * (T - T_ref)); C += conductivity_variation; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::computeKgradT(const GhostType & ghost_type,bool compute_conductivity) { if (compute_conductivity) computeConductivityOnQuadPoints(ghost_type); const Mesh::ConnectivityTypeList & type_list = this->getFEEngine().getMesh().getConnectivityTypeList(ghost_type); Mesh::ConnectivityTypeList::const_iterator it; for(it = type_list.begin(); it != type_list.end(); ++it) { const ElementType & type = *it; if(Mesh::getSpatialDimension(*it) != spatial_dimension) continue; Array & gradient = temperature_gradient(*it, ghost_type); this->getFEEngine().gradientOnIntegrationPoints(*temperature, gradient, 1 ,*it, ghost_type); Array::matrix_iterator C_it = conductivity_on_qpoints(*it, ghost_type).begin(spatial_dimension, spatial_dimension); Array::vector_iterator BT_it = gradient.begin(spatial_dimension); Array::vector_iterator k_BT_it = k_gradt_on_qpoints(type, ghost_type).begin(spatial_dimension); Array::vector_iterator k_BT_end = k_gradt_on_qpoints(type, ghost_type).end(spatial_dimension); for (;k_BT_it != k_BT_end; ++k_BT_it, ++BT_it, ++C_it) { Vector & k_BT = *k_BT_it; Vector & BT = *BT_it; Matrix & C = *C_it; k_BT.mul(C, BT); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::updateResidual(const GhostType & ghost_type, bool compute_conductivity) { AKANTU_DEBUG_IN(); const Mesh::ConnectivityTypeList & type_list = this->getFEEngine().getMesh().getConnectivityTypeList(ghost_type); Mesh::ConnectivityTypeList::const_iterator it; for(it = type_list.begin(); it != type_list.end(); ++it) { if(Mesh::getSpatialDimension(*it) != spatial_dimension) continue; Array & shapes_derivatives = const_cast &>(getFEEngine().getShapesDerivatives(*it,ghost_type)); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); // compute k \grad T computeKgradT(ghost_type,compute_conductivity); Array::vector_iterator k_BT_it = k_gradt_on_qpoints(*it,ghost_type).begin(spatial_dimension); Array::matrix_iterator B_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array::vector_iterator Bt_k_BT_it = bt_k_gT(*it,ghost_type).begin(nb_nodes_per_element); Array::vector_iterator Bt_k_BT_end = bt_k_gT(*it,ghost_type).end(nb_nodes_per_element); for (;Bt_k_BT_it != Bt_k_BT_end; ++Bt_k_BT_it, ++B_it, ++k_BT_it) { Vector & k_BT = *k_BT_it; Vector & Bt_k_BT = *Bt_k_BT_it; Matrix & B = *B_it; Bt_k_BT.mul(B, k_BT); } this->getFEEngine().integrate(bt_k_gT(*it,ghost_type), int_bt_k_gT(*it,ghost_type), nb_nodes_per_element, *it,ghost_type); this->getFEEngine().assembleArray(int_bt_k_gT(*it,ghost_type), *residual, dof_synchronizer->getLocalDOFEquationNumbers(), 1, *it,ghost_type, empty_filter, -1); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::solveExplicitLumped() { AKANTU_DEBUG_IN(); /// finally @f$ r -= C \dot T @f$ // lumped C UInt nb_nodes = temperature_rate->getSize(); UInt nb_degree_of_freedom = temperature_rate->getNbComponent(); Real * capacity_val = capacity_lumped->storage(); Real * temp_rate_val = temperature_rate->storage(); Real * res_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *res_val -= *capacity_val * *temp_rate_val; } blocked_dofs_val++; res_val++; capacity_val++; temp_rate_val++; } #ifndef AKANTU_NDEBUG getSynchronizerRegistry().synchronize(akantu::_gst_htm_gradient_temperature); #endif capacity_val = capacity_lumped->storage(); res_val = residual->storage(); blocked_dofs_val = blocked_dofs->storage(); Real * inc = increment->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *inc = (*res_val / *capacity_val); } res_val++; blocked_dofs_val++; inc++; capacity_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::explicitPred() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(integrator, "integrator was not instanciated"); integrator->integrationSchemePred(time_step, *temperature, *temperature_rate, *blocked_dofs); UInt nb_nodes = temperature->getSize(); UInt nb_degree_of_freedom = temperature->getNbComponent(); Real * temp = temperature->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n, ++temp) if(*temp < 0.) *temp = 0.; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::explicitCorr() { AKANTU_DEBUG_IN(); integrator->integrationSchemeCorrTempRate(time_step, *temperature, *temperature_rate, *blocked_dofs, *increment); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::implicitPred(){ AKANTU_DEBUG_IN(); if(method == _implicit_dynamic) integrator->integrationSchemePred(time_step, *temperature, *temperature_rate, *blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::implicitCorr(){ AKANTU_DEBUG_IN(); if(method == _implicit_dynamic) { integrator->integrationSchemeCorrTemp(time_step, *temperature, *temperature_rate, *blocked_dofs, *increment); } else { UInt nb_nodes = temperature->getSize(); UInt nb_degree_of_freedom = temperature->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * temp_val = temperature->storage(); bool * boun_val = blocked_dofs->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++temp_val, ++incr_val, ++boun_val){ *incr_val *= (1. - *boun_val); *temp_val += *incr_val; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real el_size; Real min_el_size = std::numeric_limits::max(); Real conductivitymax = conductivity(0, 0); //get the biggest parameter from k11 until k33// for(UInt i = 0; i < spatial_dimension; i++) for(UInt j = 0; j < spatial_dimension; j++) conductivitymax = std::max(conductivity(i, j), conductivitymax); const Mesh::ConnectivityTypeList & type_list = getFEEngine().getMesh().getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; for(it = type_list.begin(); it != type_list.end(); ++it) { if(getFEEngine().getMesh().getSpatialDimension(*it) != spatial_dimension) continue; UInt nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(*it); Array coord(0, nb_nodes_per_element*spatial_dimension); FEEngine::extractNodalToElementField(getFEEngine().getMesh(), getFEEngine().getMesh().getNodes(), coord, *it, _not_ghost); Array::matrix_iterator el_coord = coord.begin(spatial_dimension, nb_nodes_per_element); UInt nb_element = getFEEngine().getMesh().getNbElement(*it); for (UInt el = 0; el < nb_element; ++el, ++el_coord) { el_size = getFEEngine().getElementInradius(*el_coord, *it); min_el_size = std::min(min_el_size, el_size); } AKANTU_DEBUG_INFO("The minimum element size : " << min_el_size << " and the max conductivity is : " << conductivitymax); } Real min_dt = 2 * min_el_size * min_el_size * density * capacity / conductivitymax; StaticCommunicator::getStaticCommunicator().allReduce(&min_dt, 1, _so_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ void HeatTransferModel::readMaterials() { std::pair sub_sect = this->parser->getSubSections(_st_heat); Parser::const_section_iterator it = sub_sect.first; const ParserSection & section = *it; this->parseSection(section); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::initFull(const ModelOptions & options){ Model::initFull(options); readMaterials(); const HeatTransferModelOptions & my_options = dynamic_cast(options); method = my_options.analysis_method; //initialize the vectors initArrays(); temperature->clear(); temperature_rate->clear(); external_heat_rate->clear(); // initialize pbc if(pbc_pair.size()!=0) initPBC(); if (method == _explicit_lumped_capacity){ integrator = new ForwardEuler(); } if (method == _implicit_dynamic) { initImplicit(true); } if (method == _static) { initImplicit(false); } } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleCapacity() { AKANTU_DEBUG_IN(); if(!capacity_matrix) { std::stringstream sstr; sstr << id << ":capacity_matrix"; capacity_matrix = new SparseMatrix(*jacobian_matrix, sstr.str(), memory_id); } assembleCapacity(_not_ghost); // assembleMass(_ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::assembleCapacity(GhostType ghost_type) { AKANTU_DEBUG_IN(); MyFEEngineType & fem = getFEEngineClass(); Array rho_1(0,1); //UInt nb_element; capacity_matrix->clear(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { ElementType type = *it; computeRho(rho_1, type, ghost_type); fem.assembleFieldMatrix(rho_1, 1, *capacity_matrix, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void HeatTransferModel::computeRho(Array & rho, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); FEEngine & fem = this->getFEEngine(); UInt nb_element = fem.getMesh().getNbElement(type,ghost_type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); rho.resize(nb_element * nb_quadrature_points); Real * rho_1_val = rho.storage(); /// compute @f$ rho @f$ for each nodes of each element for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_quadrature_points; ++n) { *rho_1_val++ = this->capacity; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<> bool HeatTransferModel::testConvergence<_scc_increment>(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); UInt nb_nodes = temperature->getSize(); UInt nb_degree_of_freedom = temperature->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); Real * temperature_val = temperature->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val) && is_local_node) { norm[0] += *increment_val * *increment_val; norm[1] += *temperature_val * *temperature_val; } blocked_dofs_val++; increment_val++; temperature_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum); norm[0] = sqrt(norm[0]); norm[1] = sqrt(norm[1]); AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something goes wrong in the solve phase"); if (norm[1] < Math::getTolerance()) { error = norm[0]; AKANTU_DEBUG_OUT(); // cout<<"Error 1: "< Math::getTolerance()) error = norm[0] / norm[1]; else error = norm[0]; //In case the total displacement is zero! // cout<<"Error 2: "<::vector_iterator heat_rate_it = residual->begin(residual->getNbComponent()); Array::vector_iterator heat_rate_end = residual->end(residual->getNbComponent()); UInt n = 0; for(;heat_rate_it != heat_rate_end; ++heat_rate_it, ++n) { Real heat = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; Vector & heat_rate = *heat_rate_it; for (UInt i = 0; i < heat_rate.size(); ++i) { if (count_node) heat += heat_rate[i] * time_step; } ethermal += heat; } StaticCommunicator::getStaticCommunicator().allReduce(ðermal, 1, _so_sum); AKANTU_DEBUG_OUT(); return ethermal; } /* -------------------------------------------------------------------------- */ template void HeatTransferModel::getThermalEnergy(iterator Eth, Array::const_iterator T_it, Array::const_iterator T_end) const { for(;T_it != T_end; ++T_it, ++Eth) { *Eth = capacity * density * *T_it; } } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getThermalEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); Vector Eth_on_quarature_points(nb_quadrature_points); Array::iterator T_it = this->temperature_on_qpoints(type).begin(); T_it += index * nb_quadrature_points; Array::iterator T_end = T_it + nb_quadrature_points; getThermalEnergy(Eth_on_quarature_points.storage(), T_it, T_end); return getFEEngine().integrate(Eth_on_quarature_points, type, index); } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getThermalEnergy() { Real Eth = 0; Mesh & mesh = getFEEngine().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension); for(; it != last_type; ++it) { UInt nb_element = getFEEngine().getMesh().getNbElement(*it, _not_ghost); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(*it, _not_ghost); Array Eth_per_quad(nb_element * nb_quadrature_points, 1); Array::iterator T_it = this->temperature_on_qpoints(*it).begin(); Array::iterator T_end = this->temperature_on_qpoints(*it).end(); getThermalEnergy(Eth_per_quad.begin(), T_it, T_end); Eth += getFEEngine().integrate(Eth_per_quad, *it); } return Eth; } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getEnergy(const std::string & id) { AKANTU_DEBUG_IN(); Real energy = 0; if("thermal") energy = getThermalEnergy(); // reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real HeatTransferModel::getEnergy(const std::string & energy_id, const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); Real energy = 0.; if("thermal") energy = getThermalEnergy(type, index); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * HeatTransferModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map* > uint_nodal_fields; uint_nodal_fields["blocked_dofs" ] = blocked_dofs; dumper::Field * field = NULL; field = mesh.createNodalField(uint_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map* > real_nodal_fields; real_nodal_fields["temperature" ] = temperature; real_nodal_fields["temperature_rate" ] = temperature_rate; real_nodal_fields["external_heat_rate" ] = external_heat_rate; real_nodal_fields["residual" ] = residual; real_nodal_fields["capacity_lumped" ] = capacity_lumped; real_nodal_fields["increment" ] = increment; dumper::Field * field = mesh.createNodalField(real_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & element_kind){ dumper::Field * field = NULL; if(field_name == "partitions") field = mesh.createElementalField(mesh.getConnectivities(),group_name,this->spatial_dimension,element_kind); else if(field_name == "temperature_gradient"){ ElementTypeMap nb_data_per_elem = this->mesh.getNbDataPerElem(temperature_gradient,element_kind); field = mesh.createElementalField(temperature_gradient, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); } else if(field_name == "conductivity"){ ElementTypeMap nb_data_per_elem = this->mesh.getNbDataPerElem(conductivity_on_qpoints,element_kind); field = mesh.createElementalField(conductivity_on_qpoints, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); } return field; } /* -------------------------------------------------------------------------- */ #else /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & element_kind){ return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * HeatTransferModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } #endif __END_AKANTU__ diff --git a/src/model/heat_transfer/heat_transfer_model.hh b/src/model/heat_transfer/heat_transfer_model.hh index 17dc4ebcb..69dfdfc95 100644 --- a/src/model/heat_transfer/heat_transfer_model.hh +++ b/src/model/heat_transfer/heat_transfer_model.hh @@ -1,452 +1,455 @@ /** * @file heat_transfer_model.hh * * @author Guillaume Anciaux * @author Lucas Frerot * @author Srinivasa Babu Ramisetti * @author Rui Wang * @author Nicolas Richart * * @date creation: Sun May 01 2011 * @date last modification: Tue Sep 02 2014 * * @brief Model of Heat Transfer * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_HEAT_TRANSFER_MODEL_HH__ #define __AKANTU_HEAT_TRANSFER_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_types.hh" #include "aka_voigthelper.hh" #include "aka_memory.hh" #include "model.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "dumpable.hh" #include "parsable.hh" #include "solver.hh" #include "generalized_trapezoidal.hh" namespace akantu { class IntegrationScheme1stOrder; } __BEGIN_AKANTU__ struct HeatTransferModelOptions : public ModelOptions { HeatTransferModelOptions(AnalysisMethod analysis_method = _explicit_lumped_capacity ) : analysis_method(analysis_method) {} AnalysisMethod analysis_method; }; extern const HeatTransferModelOptions default_heat_transfer_model_options; class HeatTransferModel : public Model, public DataAccessor, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef FEEngineTemplate MyFEEngineType; HeatTransferModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "heat_transfer_model", const MemoryID & memory_id = 0); virtual ~HeatTransferModel() ; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// generic function to initialize everything ready for explicit dynamics void initFull(const ModelOptions & options = default_heat_transfer_model_options); /// initialize the fem object of the boundary void initFEEngineBoundary(bool create_surface = true); /// read one material file to instantiate all the materials void readMaterials(); /// allocate all vectors void initArrays(); /// register the tags associated with the parallel synchronizer void initParallel(MeshPartition * partition, DataAccessor * data_accessor=NULL); /// initialize the model void initModel(); /// init PBC synchronizer void initPBC(); /// initialize the solver and the jacobian_matrix (called by initImplicit) void initSolver(SolverOptions & solver_options); /// initialize the stuff for the implicit solver void initImplicit(bool dynamic, SolverOptions & solver_options = _solver_no_options); /// function to print the contain of the class virtual void printself(__attribute__ ((unused)) std::ostream & stream, __attribute__ ((unused)) int indent = 0) const {}; /* ------------------------------------------------------------------------ */ /* Methods for explicit */ /* ------------------------------------------------------------------------ */ public: /// compute and get the stable time step Real getStableTimeStep(); /// compute the heat flux void updateResidual(bool compute_conductivity = false); /// calculate the lumped capacity vector for heat transfer problem void assembleCapacityLumped(); /// update the temperature from the temperature rate void explicitPred(); /// update the temperature rate from the increment void explicitCorr(); /// implicit time integration predictor void implicitPred(); /// implicit time integration corrector void implicitCorr(); /// solve the system in temperature rate @f$C\delta \dot T = q_{n+1} - C \dot T_{n}@f$ /// this function needs to be run for dynamics void solveExplicitLumped(); // /// initialize the heat flux // void initializeResidual(Array &temp); // /// initialize temperature // void initializeTemperature(Array &temp); /* ------------------------------------------------------------------------ */ /* Methods for implicit */ /* ------------------------------------------------------------------------ */ public: /** * solve Kt = q **/ void solveStatic(); /// test if the system is converged template bool testConvergence(Real tolerance, Real & error); /** * solve a step (predictor + convergence loop + corrector) using the * the given convergence method (see akantu::SolveConvergenceMethod) * and the given convergence criteria (see * akantu::SolveConvergenceCriteria) **/ template bool solveStep(Real tolerance, UInt max_iteration = 100); template bool solveStep(Real tolerance, Real & error, UInt max_iteration = 100, bool do_not_factorize = false); /// assemble the conductivity matrix void assembleConductivityMatrix(bool compute_conductivity = true); /// assemble the conductivity matrix void assembleCapacity(); /// assemble the conductivity matrix void assembleCapacity(GhostType ghost_type); /// compute the capacity on quadrature points void computeRho(Array & rho, ElementType type, GhostType ghost_type); protected: /// compute A and solve @f[ A\delta u = f_ext - f_int @f] template void solve(Array &increment, Real block_val = 1., bool need_factorize = true, bool has_profile_changed = false); /// computation of the residual for the convergence loop void updateResidualInternal(); private: /// compute the heat flux on ghost types void updateResidual(const GhostType & ghost_type, bool compute_conductivity = false); /// calculate the lumped capacity vector for heat transfer problem (w ghosttype) void assembleCapacityLumped(const GhostType & ghost_type); /// assemble the conductivity matrix (w/ ghost type) template void assembleConductivityMatrix(const GhostType & ghost_type, bool compute_conductivity = true); /// assemble the conductivity matrix template void assembleConductivityMatrix(const ElementType & type, const GhostType & ghost_type, bool compute_conductivity = true); /// compute the conductivity tensor for each quadrature point in an array void computeConductivityOnQuadPoints(const GhostType & ghost_type); /// compute vector k \grad T for each quadrature point void computeKgradT(const GhostType & ghost_type,bool compute_conductivity); /// compute the thermal energy Real computeThermalEnergyByNode(); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const; inline void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const; inline void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag); inline UInt getNbDataToPack(SynchronizationTag tag) const; inline UInt getNbDataToUnpack(SynchronizationTag tag) const; inline void packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const; inline void unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: virtual dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & kind); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: inline FEEngine & getFEEngineBoundary(std::string name = ""); AKANTU_GET_MACRO(Density, density, Real); AKANTU_GET_MACRO(Capacity, capacity, Real); /// get the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the current value of the time step AKANTU_GET_MACRO(TimeStep, time_step, Real); /// set the value of the time step AKANTU_SET_MACRO(TimeStep, time_step, Real); /// get the assembled heat flux AKANTU_GET_MACRO(Residual, *residual, Array&); /// get the lumped capacity AKANTU_GET_MACRO(CapacityLumped, *capacity_lumped, Array&); /// get the boundary vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array&); /// get conductivity matrix AKANTU_GET_MACRO(ConductivityMatrix, *conductivity_matrix, const SparseMatrix&); /// get the external heat rate vector AKANTU_GET_MACRO(ExternalHeatRate, *external_heat_rate, Array&); /// get the temperature gradient AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(TemperatureGradient, temperature_gradient, Real); /// get the conductivity on q points AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ConductivityOnQpoints, conductivity_on_qpoints, Real); /// get the conductivity on q points AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(TemperatureOnQpoints, temperature_on_qpoints, Real); /// internal variables AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(KGradtOnQpoints, k_gradt_on_qpoints, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(IntBtKgT, int_bt_k_gT, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(BtKgT, bt_k_gT, Real); /// get the temperature AKANTU_GET_MACRO(Temperature, *temperature, Array &); /// get the temperature derivative AKANTU_GET_MACRO(TemperatureRate, *temperature_rate, Array &); /// get the equation number Array AKANTU_GET_MACRO(EquationNumber, *equation_number, const Array &); /// get the energy denominated by thermal Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index); /// get the energy denominated by thermal Real getEnergy(const std::string & energy_id); /// get the thermal energy for a given element Real getThermalEnergy(const ElementType & type, UInt index); /// get the thermal energy for a given element Real getThermalEnergy(); protected: /* ----------------------------------------------------------------------- */ template void getThermalEnergy(iterator Eth, Array::const_iterator T_it, Array::const_iterator T_end) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// number of iterations UInt n_iter; IntegrationScheme1stOrder * integrator; /// time step Real time_step; /// temperatures array Array * temperature; /// temperatures derivatives array Array * temperature_rate; /// increment array (@f$\delta \dot T@f$ or @f$\delta T@f$) Array * increment; /// conductivity matrix SparseMatrix * conductivity_matrix; /// capacity matrix SparseMatrix *capacity_matrix; /// jacobian matrix SparseMatrix * jacobian_matrix; /// the density Real density; /// the speed of the changing temperature ElementTypeMapArray temperature_gradient; /// temperature field on quadrature points ElementTypeMapArray temperature_on_qpoints; /// conductivity tensor on quadrature points ElementTypeMapArray conductivity_on_qpoints; /// vector k \grad T on quad points ElementTypeMapArray k_gradt_on_qpoints; /// vector \int \grad N k \grad T ElementTypeMapArray int_bt_k_gT; /// vector \grad N k \grad T ElementTypeMapArray bt_k_gT; /// external flux vector Array * external_heat_rate; /// residuals array Array * residual; /// position of a dof in the K matrix Array * equation_number; //lumped vector Array * capacity_lumped; /// boundary vector Array * blocked_dofs; //realtime Real time; ///capacity Real capacity; //conductivity matrix Matrix conductivity; //linear variation of the conductivity (for temperature dependent conductivity) Real conductivity_variation; // reference temperature for the interpretation of temperature variation Real T_ref; //the biggest parameter of conductivity matrix Real conductivitymax; /// thermal energy by element ElementTypeMapArray thermal_energy; /// Solver Solver * solver; /// analysis method AnalysisMethod method; + /// pointer to the pbc synchronizer + PBCSynchronizer * pbc_synch; + }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "heat_transfer_model_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const HeatTransferModel & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_HEAT_TRANSFER_MODEL_HH__ */ diff --git a/src/model/solid_mechanics/embedded_interface_model.cc b/src/model/solid_mechanics/embedded_interface_model.cc index 3a69618b7..cf922d8ab 100644 --- a/src/model/solid_mechanics/embedded_interface_model.cc +++ b/src/model/solid_mechanics/embedded_interface_model.cc @@ -1,210 +1,210 @@ /** * @file embedded_interface_model.cc * * @author Lucas Frérot * * @date creation: Mon Mar 9 2015 * @date last modification: Mon Mar 9 2015 * * @brief Model of Solid Mechanics with embedded interfaces * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "embedded_interface_model.hh" #include "material_reinforcement.hh" #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" # include "dumpable_inline_impl.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const EmbeddedInterfaceModelOptions default_embedded_interface_model_options(_explicit_lumped_mass, false, false); /* -------------------------------------------------------------------------- */ EmbeddedInterfaceModel::EmbeddedInterfaceModel(Mesh & mesh, Mesh & primitive_mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, spatial_dimension, id, memory_id), intersector(mesh, primitive_mesh), interface_mesh(NULL), primitive_mesh(primitive_mesh), interface_material_selector(NULL) { // This pointer should be deleted by ~SolidMechanicsModel() MaterialSelector * mat_sel_pointer = new MeshDataMaterialSelector("physical_names", *this); this->setMaterialSelector(*mat_sel_pointer); interface_mesh = &(intersector.getInterfaceMesh()); // Create 1D FEEngine on the interface mesh registerFEEngineObject("EmbeddedInterfaceFEEngine", *interface_mesh, 1); } /* -------------------------------------------------------------------------- */ EmbeddedInterfaceModel::~EmbeddedInterfaceModel() { delete interface_material_selector; } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::initFull(const ModelOptions & options) { const EmbeddedInterfaceModelOptions & eim_options = dynamic_cast(options); // We don't want to initiate materials before shape functions are initialized SolidMechanicsModelOptions dummy_options(eim_options.analysis_method, true); // Do no initialize interface_mesh if told so if (!eim_options.no_init_intersections) intersector.constructData(); // Initialize interface FEEngine FEEngine & engine = getFEEngine("EmbeddedInterfaceFEEngine"); engine.initShapeFunctions(_not_ghost); engine.initShapeFunctions(_ghost); SolidMechanicsModel::initFull(dummy_options); // This will call SolidMechanicsModel::initMaterials() last this->initMaterials(); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper("reinforcement", id); this->mesh.addDumpMeshToDumper("reinforcement", *interface_mesh, 1, _not_ghost, _ek_regular); #endif } /* -------------------------------------------------------------------------- */ // This function is very similar to SolidMechanicsModel's void EmbeddedInterfaceModel::initMaterials() { Element element; delete interface_material_selector; interface_material_selector = new InterfaceMeshDataMaterialSelector("physical_names", *this); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { element.ghost_type = *gt; Mesh::type_iterator it = interface_mesh->firstType(1, *gt); Mesh::type_iterator end = interface_mesh->lastType(1, *gt); for (; it != end ; ++it) { UInt nb_element = interface_mesh->getNbElement(*it, *gt); element.type = *it; Array & mat_indexes = material_index.alloc(nb_element, 1, *it, *gt); for (UInt el = 0 ; el < nb_element ; el++) { element.element = el; UInt mat_index = (*interface_material_selector)(element); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The material selector returned an index that does not exist"); mat_indexes(element.element) = mat_index; materials.at(mat_index)->addElement(*it, el, *gt); } } } SolidMechanicsModel::initMaterials(); } -/** - * DO NOT REMOVE - This prevents the material reinforcement to register - * their number of components. Problems arise with AvgHomogenizingFunctor - * if the material reinforcement gives its number of components for a - * field. Since AvgHomogenizingFunctor verifies that all the fields - * have the same number of components, an exception is raised. - */ -ElementTypeMap EmbeddedInterfaceModel::getInternalDataPerElem(const std::string & field_name, - const ElementKind & kind) { - if (!(this->isInternal(field_name,kind))) AKANTU_EXCEPTION("unknown internal " << field_name); - - for (UInt m = 0; m < materials.size() ; ++m) { - if (materials[m]->isInternal(field_name, kind)) { - Material * mat = NULL; - - switch(this->spatial_dimension) { - case 1: - mat = dynamic_cast *>(materials[m]); - break; - - case 2: - mat = dynamic_cast *>(materials[m]); - break; - - case 3: - mat = dynamic_cast *>(materials[m]); - break; - } - - if (mat == NULL && field_name != "stress_embedded") - return materials[m]->getInternalDataPerElem(field_name,kind); - else if (mat != NULL && field_name == "stress_embedded") - return mat->getInternalDataPerElem(field_name, kind, "EmbeddedInterfaceFEEngine"); - } - } - - return ElementTypeMap(); -} +// /** +// * DO NOT REMOVE - This prevents the material reinforcement to register +// * their number of components. Problems arise with AvgHomogenizingFunctor +// * if the material reinforcement gives its number of components for a +// * field. Since AvgHomogenizingFunctor verifies that all the fields +// * have the same number of components, an exception is raised. +// */ +// ElementTypeMap EmbeddedInterfaceModel::getInternalDataPerElem(const std::string & field_name, +// const ElementKind & kind) { +// if (!(this->isInternal(field_name,kind))) AKANTU_EXCEPTION("unknown internal " << field_name); + +// for (UInt m = 0; m < materials.size() ; ++m) { +// if (materials[m]->isInternal(field_name, kind)) { +// Material * mat = NULL; + +// switch(this->spatial_dimension) { +// case 1: +// mat = dynamic_cast *>(materials[m]); +// break; + +// case 2: +// mat = dynamic_cast *>(materials[m]); +// break; + +// case 3: +// mat = dynamic_cast *>(materials[m]); +// break; +// } + +// if (mat == NULL && field_name != "stress_embedded") +// return materials[m]->getInternalDataPerElem(field_name,kind); +// else if (mat != NULL && field_name == "stress_embedded") +// return mat->getInternalDataPerElem(field_name, kind, "EmbeddedInterfaceFEEngine"); +// } +// } + +// return ElementTypeMap(); +// } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { #ifdef AKANTU_USE_IOHELPER dumper::Field * field = NULL; // If dumper is reinforcement, create a 1D elemental field if (dumper_name == "reinforcement") field = this->createElementalField(field_id, group_name, padding_flag, 1, element_kind); else { try { SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, element_kind, padding_flag); } catch (...) {} } if (field) { DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name,group_name); Model::addDumpGroupFieldToDumper(field_id,field,dumper); } #endif } __END_AKANTU__ diff --git a/src/model/solid_mechanics/embedded_interface_model.hh b/src/model/solid_mechanics/embedded_interface_model.hh index 9dc01fc75..26c64b5c7 100644 --- a/src/model/solid_mechanics/embedded_interface_model.hh +++ b/src/model/solid_mechanics/embedded_interface_model.hh @@ -1,166 +1,166 @@ /** * @file embedded_interface_model.hh * * @author Lucas Frérot * * @date creation: Mon Mar 9 2015 * @date last modification: Mon Mar 9 2015 * * @brief Model of Solid Mechanics with embedded interfaces * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ #define __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "mesh.hh" #include "embedded_interface_intersector.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /// Options for the EmbeddedInterfaceModel struct EmbeddedInterfaceModelOptions : SolidMechanicsModelOptions { /** * @brief Constructor for EmbeddedInterfaceModelOptions * @param analysis_method see SolidMeechanicsModelOptions * @param no_init_intersections ignores the embedded elements * @param no_init_materials see SolidMeechanicsModelOptions */ EmbeddedInterfaceModelOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool no_init_intersections = false, bool no_init_materials = false): SolidMechanicsModelOptions(analysis_method, no_init_materials), no_init_intersections(no_init_intersections) {} /// Ignore the reinforcements bool no_init_intersections; }; extern const EmbeddedInterfaceModelOptions default_embedded_interface_model_options; /** * @brief Solid mechanics model using the embedded model. * * This SolidMechanicsModel subclass implements the embedded model, * a method used to represent 1D elements in a finite elements model * (eg. reinforcements in concrete). * * In addition to the SolidMechanicsModel properties, this model has * a mesh of the 1D elements embedded in the model, and an instance of the * EmbeddedInterfaceIntersector class for the computation of the intersections of the * 1D elements with the background (bulk) mesh. * * @see MaterialReinforcement */ class EmbeddedInterfaceModel : public SolidMechanicsModel { /// Same type as SolidMechanicsModel typedef FEEngineTemplate MyFEEngineType; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /** * @brief Constructor * * @param mesh main mesh (concrete) * @param primitive_mesh mesh of the embedded reinforcement */ EmbeddedInterfaceModel(Mesh & mesh, Mesh & primitive_mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "embedded_interface_model", const MemoryID & memory_id = 0); /// Destructor virtual ~EmbeddedInterfaceModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Initialise the model virtual void initFull(const ModelOptions & options = default_embedded_interface_model_options); /// Initialise the materials virtual void initMaterials(); /// Allows filtering of dump fields which need to be dumpes on interface mesh virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag); - virtual ElementTypeMap getInternalDataPerElem(const std::string & field_name, - const ElementKind & kind); + // virtual ElementTypeMap getInternalDataPerElem(const std::string & field_name, + // const ElementKind & kind); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get interface mesh AKANTU_GET_MACRO(InterfaceMesh, *interface_mesh, Mesh &); /// Get associated elements AKANTU_GET_MACRO_BY_ELEMENT_TYPE(InterfaceAssociatedElements, interface_mesh->getData("associated_element"), Element); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Intersector object to build the interface mesh EmbeddedInterfaceIntersector intersector; /// Interface mesh (weak reference) Mesh * interface_mesh; /// Mesh used to create the CGAL primitives for intersections Mesh & primitive_mesh; /// Material selector for interface MaterialSelector * interface_material_selector; }; /// Material selector based on mesh data for interface elements template class InterfaceMeshDataMaterialSelector : public ElementDataMaterialSelector { public: InterfaceMeshDataMaterialSelector(const std::string & name, const EmbeddedInterfaceModel & model, UInt first_index = 1) : ElementDataMaterialSelector(model.getInterfaceMesh().getData(name), model, first_index) {} }; __END_AKANTU__ #endif // __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 16ad287f0..57b7b421f 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1689 +1,1566 @@ /** * @file material.cc * * @author Aurelia Isabel Cuba Ramos * @author Marco Vocialta * @author Nicolas Richart * @author Daniel Pino Muñoz * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Implementation of the common part of the material class * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "solid_mechanics_model.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Memory(id, model.getMemoryID()), Parsable(_st_material, id), is_init(false), fem(&(model.getFEEngine())), finite_deformation(false), name(""), model(&model), spatial_dimension(this->model->getSpatialDimension()), element_filter("element_filter", id, this->memory_id), stress("stress", *this), eigengradu("eigen_grad_u", *this), gradu("grad_u", *this), green_strain("green_strain",*this), piola_kirchhoff_2("piola_kirchhoff_2", *this), potential_energy("potential_energy", *this), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse coordinates", *this), interpolation_points_matrices("interpolation points matrices", *this) { AKANTU_DEBUG_IN(); /// for each connectivity types allocate the element filer array of the material model.getMesh().initElementTypeMapArray(element_filter, 1, spatial_dimension, false, _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Memory(id, model.getMemoryID()), Parsable(_st_material, id), is_init(false), fem(&(model.getFEEngine())), finite_deformation(false), name(""), model(&model), spatial_dimension(dim), element_filter("element_filter", id, this->memory_id), stress("stress", *this, dim, fe_engine, this->element_filter), eigengradu("eigen_grad_u", *this, dim, fe_engine, this->element_filter), gradu("gradu", *this, dim, fe_engine, this->element_filter), green_strain("green_strain", *this, dim, fe_engine, this->element_filter), piola_kirchhoff_2("poila_kirchhoff_2", *this, dim, fe_engine, this->element_filter), potential_energy("potential_energy", *this, dim, fe_engine, this->element_filter), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse_coordinates", *this, dim, fe_engine, this->element_filter), interpolation_points_matrices("interpolation points matrices", *this, dim, fe_engine, this->element_filter) { AKANTU_DEBUG_IN(); mesh.initElementTypeMapArray(element_filter, 1, spatial_dimension, false, _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::~Material() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::initialize() { registerParam("rho" , rho , Real(0.) , _pat_parsable | _pat_modifiable, "Density"); registerParam("name" , name , std::string(), _pat_parsable | _pat_readable); registerParam("finite_deformation" , finite_deformation , false , _pat_parsable | _pat_readable, "Is finite deformation"); registerParam("inelastic_deformation", inelastic_deformation, false , _pat_internal, "Is inelastic deformation"); /// allocate gradu stress for local elements eigengradu.initialize(spatial_dimension * spatial_dimension); gradu.initialize(spatial_dimension * spatial_dimension); stress.initialize(spatial_dimension * spatial_dimension); potential_energy.initialize(1); this->model->registerEventHandler(*this); } /* -------------------------------------------------------------------------- */ void Material::initMaterial() { AKANTU_DEBUG_IN(); if(finite_deformation) { this->piola_kirchhoff_2.initialize(spatial_dimension * spatial_dimension); if(use_previous_stress) this->piola_kirchhoff_2.initializeHistory(); this->green_strain.initialize(spatial_dimension * spatial_dimension); } if(use_previous_stress) this->stress.initializeHistory(); if(use_previous_gradu) this->gradu.initializeHistory(); for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); is_init = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { if(it->second->hasHistory()) it->second->saveCurrentValues(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the residual by assembling @f$\int_{e} \sigma_e \frac{\partial * \varphi}{\partial X} dX @f$ * * @param[in] displacements nodes displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::updateResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); computeAllStresses(ghost_type); assembleResidual(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model->getSpatialDimension(); if(!finite_deformation){ Array & residual = const_cast &>(model->getResidual()); Mesh & mesh = fem->getMesh(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element) { const Array & shapes_derivatives = fem->getShapesDerivatives(*it, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = fem->getNbIntegrationPoints(*it, ghost_type); /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by @f$\mathbf{B}^t \mathbf{\sigma}_q@f$ Array * sigma_dphi_dx = new Array(nb_element*nb_quadrature_points, size_of_shapes_derivatives, "sigma_x_dphi_/_dX"); Array * shapesd_filtered = new Array(0, size_of_shapes_derivatives, "filtered shapesd"); FEEngine::filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, *it, ghost_type, elem_filter); Array & stress_vect = this->stress(*it, ghost_type); Array::matrix_iterator sigma = stress_vect.begin(spatial_dimension, spatial_dimension); Array::matrix_iterator B = shapesd_filtered->begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator Bt_sigma_it = sigma_dphi_dx->begin(spatial_dimension, nb_nodes_per_element); for (UInt q = 0; q < nb_element*nb_quadrature_points; ++q, ++sigma, ++B, ++Bt_sigma_it) Bt_sigma_it->mul(*sigma, *B); delete shapesd_filtered; /** * compute @f$\int \sigma * \frac{\partial \varphi}{\partial X}dX@f$ by @f$ \sum_q \mathbf{B}^t * \mathbf{\sigma}_q \overline w_q J_q@f$ */ Array * int_sigma_dphi_dx = new Array(nb_element, nb_nodes_per_element * spatial_dimension, "int_sigma_x_dphi_/_dX"); fem->integrate(*sigma_dphi_dx, *int_sigma_dphi_dx, size_of_shapes_derivatives, *it, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble fem->assembleArray(*int_sigma_dphi_dx, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, elem_filter, -1); delete int_sigma_dphi_dx; } } } else{ switch (spatial_dimension){ case 1: this->assembleResidual<1>(ghost_type); break; case 2: this->assembleResidual<2>(ghost_type); break; case 3: this->assembleResidual<3>(ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stress from the gradu * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model->getSpatialDimension(); Mesh::type_iterator it = fem->getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = fem->getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); if (elem_filter.getSize() == 0) continue; Array & gradu_vect = gradu(*it, ghost_type); /// compute @f$\nabla u@f$ fem->gradientOnIntegrationPoints(model->getDisplacement(), gradu_vect, spatial_dimension, *it, ghost_type, elem_filter); gradu_vect -= eigengradu(*it, ghost_type); /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$ computeStress(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllCauchyStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(finite_deformation,"The Cauchy stress can only be computed if you are working in finite deformation."); //resizeInternalArray(stress); Mesh::type_iterator it = fem->getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = fem->getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) switch (spatial_dimension){ case 1: this->computeCauchyStress<1>(*it, ghost_type); break; case 2: this->computeCauchyStress<2>(*it, ghost_type); break; case 3: this->computeCauchyStress<3>(*it, ghost_type); break; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::computeCauchyStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array::matrix_iterator gradu_it = this->gradu(el_type, ghost_type).begin(dim, dim); Array::matrix_iterator gradu_end = this->gradu(el_type, ghost_type).end(dim, dim); Array::matrix_iterator piola_it = this->piola_kirchhoff_2(el_type, ghost_type).begin(dim, dim); Array::matrix_iterator stress_it = this->stress(el_type, ghost_type).begin(dim, dim); Matrix F_tensor(dim, dim); for (; gradu_it != gradu_end; ++gradu_it, ++piola_it, ++stress_it) { Matrix & grad_u = *gradu_it; Matrix & piola = *piola_it; Matrix & sigma = *stress_it; gradUToF (grad_u, F_tensor); this->computeCauchyStressOnQuad(F_tensor, piola, sigma); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::setToSteadyState(GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array & displacement = model->getDisplacement(); //resizeInternalArray(gradu); UInt spatial_dimension = model->getSpatialDimension(); Mesh::type_iterator it = fem->getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = fem->getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); Array & gradu_vect = gradu(*it, ghost_type); /// compute @f$\nabla u@f$ fem->gradientOnIntegrationPoints(displacement, gradu_vect, spatial_dimension, *it, ghost_type, elem_filter); setToSteadyState(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stiffness matrix by assembling @f$\int_{\omega} B^t \times D * \times B d\omega @f$ * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model->getSpatialDimension(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { if(finite_deformation){ switch (spatial_dimension) { case 1: { assembleStiffnessMatrixNL < 1 > (*it, ghost_type); assembleStiffnessMatrixL2 < 1 > (*it, ghost_type); break; } case 2: { assembleStiffnessMatrixNL < 2 > (*it, ghost_type); assembleStiffnessMatrixL2 < 2 > (*it, ghost_type); break; } case 3: { assembleStiffnessMatrixNL < 3 > (*it, ghost_type); assembleStiffnessMatrixL2 < 3 > (*it, ghost_type); break; } } } else { switch(spatial_dimension) { case 1: { assembleStiffnessMatrix<1>(*it, ghost_type); break; } case 2: { assembleStiffnessMatrix<2>(*it, ghost_type); break; } case 3: { assembleStiffnessMatrix<3>(*it, ghost_type); break; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array & elem_filter = element_filter(type, ghost_type); if (elem_filter.getSize()) { SparseMatrix & K = const_cast(model->getStiffnessMatrix()); const Array & shapes_derivatives = fem->getShapesDerivatives(type, ghost_type); Array & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem->getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem->gradientOnIntegrationPoints(model->getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array * tangent_stiffness_matrix = new Array(nb_element*nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); Array * shapesd_filtered = new Array(0, dim * nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(fem->getMesh(), shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array * bt_d_b = new Array(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix B(tangent_size, dim * nb_nodes_per_element); Matrix Bt_D(dim * nb_nodes_per_element, tangent_size); Array::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array::matrix_iterator Bt_D_B_it = bt_d_b->begin(dim*nb_nodes_per_element, dim*nb_nodes_per_element); Array::matrix_iterator D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); Array::matrix_iterator D_end = tangent_stiffness_matrix->end (tangent_size, tangent_size); for(; D_it != D_end; ++D_it, ++Bt_D_B_it, ++shapes_derivatives_filtered_it) { Matrix & D = *D_it; Matrix & Bt_D_B = *Bt_D_B_it; VoigtHelper::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_D.mul(B, D); Bt_D_B.mul(Bt_D, B); } delete tangent_stiffness_matrix; delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * K_e = new Array(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem->integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; fem->assembleMatrix(*K_e, K, spatial_dimension, type, ghost_type, elem_filter); delete K_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast (model->getStiffnessMatrix()); const Array & shapes_derivatives = fem->getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); //Array & gradu_vect = delta_gradu(type, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem->getNbIntegrationPoints(type, ghost_type); //gradu_vect.resize(nb_quadrature_points * nb_element); // fem->gradientOnIntegrationPoints(model->getIncrement(), gradu_vect, // dim, type, ghost_type, &elem_filter); Array * shapes_derivatives_filtered = new Array (nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); Array::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_s_b_size = dim * nb_nodes_per_element; Array * bt_s_b = new Array (nb_element * nb_quadrature_points, bt_s_b_size * bt_s_b_size, "B^t*D*B"); UInt piola_matrix_size = getCauchyStressMatrixSize(dim); Matrix B(piola_matrix_size, bt_s_b_size); Matrix Bt_S(bt_s_b_size, piola_matrix_size); Matrix S(piola_matrix_size, piola_matrix_size); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size); Array::matrix_iterator Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size); Array::matrix_iterator piola_it = piola_kirchhoff_2(type, ghost_type).begin(dim, dim); for (; Bt_S_B_it != Bt_S_B_end; ++Bt_S_B_it, ++shapes_derivatives_filtered_it, ++piola_it) { Matrix & Bt_S_B = *Bt_S_B_it; Matrix & Piola_kirchhoff_matrix = *piola_it; setCauchyStressMatrix< dim >(Piola_kirchhoff_matrix, S); VoigtHelper::transferBMatrixToBNL(*shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_S.mul < true, false > (B, S); Bt_S_B.mul < false, false > (Bt_S, B); } delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * K_e = new Array (nb_element, bt_s_b_size * bt_s_b_size, "K_e"); fem->integrate(*bt_s_b, *K_e, bt_s_b_size * bt_s_b_size, type, ghost_type, elem_filter); delete bt_s_b; fem->assembleMatrix(*K_e, K, spatial_dimension, type, ghost_type, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast (model->getStiffnessMatrix()); const Array & shapes_derivatives = fem->getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); Array & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem->getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem->gradientOnIntegrationPoints(model->getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array * tangent_stiffness_matrix = new Array (nb_element*nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); Array * shapes_derivatives_filtered = new Array (nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); Array::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array * bt_d_b = new Array (nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix B(tangent_size, dim * nb_nodes_per_element); Matrix B2(tangent_size, dim * nb_nodes_per_element); Matrix Bt_D(dim * nb_nodes_per_element, tangent_size); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator Bt_D_B_it = bt_d_b->begin(dim*nb_nodes_per_element, dim * nb_nodes_per_element); Array::matrix_iterator grad_u_it = gradu_vect.begin(dim, dim); Array::matrix_iterator D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); Array::matrix_iterator D_end = tangent_stiffness_matrix->end(tangent_size, tangent_size); for (; D_it != D_end; ++D_it, ++Bt_D_B_it, ++shapes_derivatives_filtered_it, ++grad_u_it) { Matrix & grad_u = *grad_u_it; Matrix & D = *D_it; Matrix & Bt_D_B = *Bt_D_B_it; //transferBMatrixToBL1 (*shapes_derivatives_filtered_it, B, nb_nodes_per_element); VoigtHelper::transferBMatrixToSymVoigtBMatrix(*shapes_derivatives_filtered_it, B, nb_nodes_per_element); VoigtHelper::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2, nb_nodes_per_element); B += B2; Bt_D.mul < true, false > (B, D); Bt_D_B.mul < false, false > (Bt_D, B); } delete tangent_stiffness_matrix; delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * K_e = new Array (nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem->integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; fem->assembleMatrix(*K_e, K, spatial_dimension, type, ghost_type, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleResidual(GhostType ghost_type){ AKANTU_DEBUG_IN(); Array & residual = const_cast &> (model->getResidual()); Mesh & mesh = fem->getMesh(); Mesh::type_iterator it = element_filter.firstType(dim, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(dim, ghost_type); for (; it != last_type; ++it) { const Array & shapes_derivatives = fem->getShapesDerivatives(*it, ghost_type); Array & elem_filter = element_filter(*it, ghost_type); if (elem_filter.getSize() == 0) continue; UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_element = elem_filter.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = fem->getNbIntegrationPoints(*it, ghost_type); Array * shapesd_filtered = new Array(0, size_of_shapes_derivatives, "filtered shapesd"); FEEngine::filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, *it, ghost_type, elem_filter); Array::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); //Set stress vectors UInt stress_size = getTangentStiffnessVoigtSize(dim); //Set matrices B and BNL* UInt bt_s_size = dim * nb_nodes_per_element; Array * bt_s = new Array (nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); Array::matrix_iterator grad_u_it = this->gradu(*it, ghost_type).begin(dim, dim); Array::matrix_iterator grad_u_end = this->gradu(*it, ghost_type).end(dim, dim); Array::matrix_iterator stress_it = this->piola_kirchhoff_2(*it, ghost_type).begin(dim, dim); shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array::matrix_iterator bt_s_it = bt_s->begin(bt_s_size, 1); Matrix S_vect(stress_size, 1); Matrix B_tensor(stress_size, bt_s_size); Matrix B2_tensor(stress_size, bt_s_size); for (; grad_u_it != grad_u_end; ++grad_u_it, ++stress_it, ++shapes_derivatives_filtered_it, ++bt_s_it) { Matrix & grad_u = *grad_u_it; Matrix & r_it = *bt_s_it; Matrix & S_it = *stress_it; setCauchyStressArray (S_it, S_vect); VoigtHelper::transferBMatrixToSymVoigtBMatrix(*shapes_derivatives_filtered_it, B_tensor, nb_nodes_per_element); VoigtHelper::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2_tensor, nb_nodes_per_element); B_tensor += B2_tensor; r_it.mul < true, false > (B_tensor, S_vect); } delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * r_e = new Array (nb_element, bt_s_size, "r_e"); fem->integrate(*bt_s, *r_e, bt_s_size, *it, ghost_type, elem_filter); delete bt_s; fem->assembleArray(*r_e, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, elem_filter, -1); delete r_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllStressesFromTangentModuli(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model->getSpatialDimension(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { switch(spatial_dimension) { case 1: { computeAllStressesFromTangentModuli<1>(*it, ghost_type); break; } case 2: { computeAllStressesFromTangentModuli<2>(*it, ghost_type); break; } case 3: { computeAllStressesFromTangentModuli<3>(*it, ghost_type); break; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::computeAllStressesFromTangentModuli(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array & shapes_derivatives = fem->getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); Array & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem->getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); Array & disp = model->getDisplacement(); fem->gradientOnIntegrationPoints(disp, gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_moduli_size = getTangentStiffnessVoigtSize(dim); Array * tangent_moduli_tensors = new Array(nb_element*nb_quadrature_points, tangent_moduli_size * tangent_moduli_size, "tangent_moduli_tensors"); tangent_moduli_tensors->clear(); computeTangentModuli(type, *tangent_moduli_tensors, ghost_type); Array * shapesd_filtered = new Array(0, dim* nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(fem->getMesh(), shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); Array filtered_u(nb_element, nb_nodes_per_element * spatial_dimension); FEEngine::extractNodalToElementField(fem->getMesh(), disp, filtered_u, type, ghost_type, elem_filter); /// compute @f$\mathbf{D} \mathbf{B} \mathbf{u}@f$ Array::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array::matrix_iterator D_it = tangent_moduli_tensors->begin(tangent_moduli_size, tangent_moduli_size); Array::matrix_iterator sigma_it = stress(type, ghost_type).begin(spatial_dimension, spatial_dimension); Array::vector_iterator u_it = filtered_u.begin(spatial_dimension * nb_nodes_per_element); Matrix B(tangent_moduli_size, spatial_dimension * nb_nodes_per_element); Vector Bu(tangent_moduli_size); Vector DBu(tangent_moduli_size); for (UInt e = 0; e < nb_element; ++e, ++u_it) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it, ++shapes_derivatives_filtered_it, ++sigma_it) { Vector & u = *u_it; Matrix & sigma = *sigma_it; Matrix & D = *D_it; VoigtHelper::transferBMatrixToSymVoigtBMatrix(*shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bu.mul(B, u); DBu.mul(D, Bu); // Voigt notation to full symmetric tensor for (UInt i = 0; i < dim; ++i) sigma(i, i) = DBu(i); if(dim == 2) { sigma(0,1) = sigma(1,0) = DBu(2); } else if(dim == 3) { sigma(1,2) = sigma(2,1) = DBu(3); sigma(0,2) = sigma(2,0) = DBu(4); sigma(0,1) = sigma(1,0) = DBu(5); } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergyByElements() { AKANTU_DEBUG_IN(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension); for(; it != last_type; ++it) { computePotentialEnergy(*it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real epot = 0.; computePotentialEnergyByElements(); /// integrate the potential energy for each type of elements Mesh::type_iterator it = element_filter.firstType(spatial_dimension); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension); for(; it != last_type; ++it) { epot += fem->integrate(potential_energy(*it, _not_ghost), *it, _not_ghost, element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy(ElementType & type, UInt index) { AKANTU_DEBUG_IN(); Real epot = 0.; Vector epot_on_quad_points(fem->getNbIntegrationPoints(type)); computePotentialEnergyByElement(type, index, epot_on_quad_points); epot = fem->integrate(epot_on_quad_points, type, element_filter(type)(index)); AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(std::string type) { AKANTU_DEBUG_IN(); if(type == "potential") return getPotentialEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(std::string energy_id, ElementType type, UInt index) { AKANTU_DEBUG_IN(); if(energy_id == "potential") return getPotentialEnergy(type, index); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ void Material::initElementalFieldInterpolation(const ElementTypeMapArray & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); this->fem->initElementalFieldInterpolationFromIntegrationPoints(interpolation_points_coordinates, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, &(this->element_filter)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(ElementTypeMapArray & result, const GhostType ghost_type) { this->fem->interpolateElementalFieldFromIntegrationPoints(this->stress, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, result, ghost_type, &(this->element_filter)); } /* -------------------------------------------------------------------------- */ void Material::interpolateStressOnFacets(ElementTypeMapArray & result, ElementTypeMapArray & by_elem_result, const GhostType ghost_type) { interpolateStress(by_elem_result, ghost_type); UInt stress_size = this->stress.getNbComponent(); const Mesh & mesh = this->model->getMesh(); const Mesh & mesh_facets = mesh.getMeshFacets(); Mesh::type_iterator it = this->element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = this->element_filter.lastType(spatial_dimension, ghost_type); for (; it != last; ++it) { ElementType type = *it; Array & elem_fil = element_filter(type, ghost_type); Array & by_elem_res = by_elem_result(type, ghost_type); UInt nb_element = elem_fil.getSize(); UInt nb_element_full = this->model->getMesh().getNbElement(type, ghost_type); UInt nb_interpolation_points_per_elem = by_elem_res.getSize() / nb_element_full; const Array & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); UInt nb_quad_per_facet = nb_interpolation_points_per_elem / nb_facet_per_elem; Element element_for_comparison(type, 0, ghost_type); const Array< std::vector > * element_to_facet = NULL; GhostType current_ghost_type = _casper; Array * result_vec = NULL; Array::const_matrix_iterator result_it = by_elem_res.begin_reinterpret(stress_size, nb_interpolation_points_per_elem, nb_element_full); for (UInt el = 0; el < nb_element; ++el){ UInt global_el = elem_fil(el); element_for_comparison.element = global_el; for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element facet_elem = facet_to_element(global_el, f); UInt global_facet = facet_elem.element; if (facet_elem.ghost_type != current_ghost_type) { current_ghost_type = facet_elem.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement(type_facet, current_ghost_type); result_vec = &result(type_facet, current_ghost_type); } bool is_second_element = (*element_to_facet)(global_facet)[0] != element_for_comparison; for (UInt q = 0; q < nb_quad_per_facet; ++q) { Vector result_local(result_vec->storage() + (global_facet * nb_quad_per_facet + q) * result_vec->getNbComponent() + is_second_element * stress_size, stress_size); const Matrix & result_tmp(result_it[global_el]); result_local = result_tmp(f * nb_quad_per_facet + q); } } } } } /* -------------------------------------------------------------------------- */ template const Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template<> const Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch(debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" < Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch(debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template<> const Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch(debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" < Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch(debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template const InternalField & Material::getInternal(const ID & int_id) const { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template InternalField & Material::getInternal(const ID & int_id) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template<> const InternalField & Material::getInternal(const ID & int_id) const { std::map *>::const_iterator it = internal_vectors_real.find(getID() + ":" + int_id); if(it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template<> InternalField & Material::getInternal(const ID & int_id) { std::map *>::iterator it = internal_vectors_real.find(getID() + ":" + int_id); if(it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template<> const InternalField & Material::getInternal(const ID & int_id) const { std::map *>::const_iterator it = internal_vectors_uint.find(getID() + ":" + int_id); if(it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template<> InternalField & Material::getInternal(const ID & int_id) { std::map *>::iterator it = internal_vectors_uint.find(getID() + ":" + int_id); if(it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ void Material::addElements(const Array & elements_to_add) { AKANTU_DEBUG_IN(); UInt mat_id = model->getInternalIndexFromID(getID()); Array::const_iterator el_begin = elements_to_add.begin(); Array::const_iterator el_end = elements_to_add.end(); for(;el_begin != el_end; ++el_begin) { const Element & element = *el_begin; Array & mat_indexes = model->getMaterialByElement (element.type, element.ghost_type); Array & mat_loc_num = model->getMaterialLocalNumbering(element.type, element.ghost_type); UInt index = this->addElement(element.type, element.element, element.ghost_type); mat_indexes(element.element) = mat_id; mat_loc_num(element.element) = index; } this->resizeInternals(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::removeElements(const Array & elements_to_remove) { AKANTU_DEBUG_IN(); Array::const_iterator el_begin = elements_to_remove.begin(); Array::const_iterator el_end = elements_to_remove.end(); if(el_begin==el_end) return; ElementTypeMapArray material_local_new_numbering("remove mat filter elem", getID()); Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; element.ghost_type = ghost_type; ElementTypeMapArray::type_iterator it = element_filter.firstType(_all_dimensions, ghost_type, _ek_not_defined); ElementTypeMapArray::type_iterator end = element_filter.lastType(_all_dimensions, ghost_type, _ek_not_defined); for(; it != end; ++it) { ElementType type = *it; element.type = type; Array & elem_filter = this->element_filter(type, ghost_type); Array & mat_loc_num = this->model->getMaterialLocalNumbering(type, ghost_type); if(!material_local_new_numbering.exists(type, ghost_type)) material_local_new_numbering.alloc(elem_filter.getSize(), 1, type, ghost_type); Array & mat_renumbering = material_local_new_numbering(type, ghost_type); UInt nb_element = elem_filter.getSize(); element.kind=(*el_begin).kind; Array elem_filter_tmp; UInt new_id = 0; for (UInt el = 0; el < nb_element; ++el) { element.element = elem_filter(el); if(std::find(el_begin, el_end, element) == el_end) { elem_filter_tmp.push_back(element.element); mat_renumbering(el) = new_id; mat_loc_num(element.element) = new_id; ++new_id; } else { mat_renumbering(el) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.getSize()); elem_filter.copy(elem_filter_tmp); } } for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::resizeInternals() { AKANTU_DEBUG_IN(); for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::onElementsAdded(__attribute__((unused)) const Array & element_list, __attribute__((unused)) const NewElementsEvent & event) { this->resizeInternals(); } /* -------------------------------------------------------------------------- */ void Material::onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { UInt my_num = model->getInternalIndexFromID(getID()); ElementTypeMapArray material_local_new_numbering("remove mat filter elem", getID()); Array::const_iterator el_begin = element_list.begin(); Array::const_iterator el_end = element_list.end(); for (ghost_type_t::iterator g = ghost_type_t::begin(); g != ghost_type_t::end(); ++g) { GhostType gt = *g; ElementTypeMapArray::type_iterator it = new_numbering.firstType(_all_dimensions, gt, _ek_not_defined); ElementTypeMapArray::type_iterator end = new_numbering.lastType (_all_dimensions, gt, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; if(element_filter.exists(type, gt) && element_filter(type, gt).getSize()){ Array & elem_filter = element_filter(type, gt); Array & mat_indexes = this->model->getMaterialByElement (*it, gt); Array & mat_loc_num = this->model->getMaterialLocalNumbering(*it, gt); UInt nb_element = this->model->getMesh().getNbElement(type, gt); // all materials will resize of the same size... mat_indexes.resize(nb_element); mat_loc_num.resize(nb_element); if(!material_local_new_numbering.exists(type, gt)) material_local_new_numbering.alloc(elem_filter.getSize(), 1, type, gt); Array & mat_renumbering = material_local_new_numbering(type, gt); const Array & renumbering = new_numbering(type, gt); Array elem_filter_tmp; UInt ni = 0; Element el; el.type = type; el.ghost_type = gt; el.kind = Mesh::getKind(type); for (UInt i = 0; i < elem_filter.getSize(); ++i) { el.element = elem_filter(i); if(std::find(el_begin, el_end, el) == el_end) { UInt new_el = renumbering(el.element); AKANTU_DEBUG_ASSERT(new_el != UInt(-1), "A not removed element as been badly renumbered"); elem_filter_tmp.push_back(new_el); mat_renumbering(i) = ni; mat_indexes(new_el) = my_num; mat_loc_num(new_el) = ni; ++ni; } else { mat_renumbering(i) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.getSize()); elem_filter.copy(elem_filter_tmp); } } } for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); } /* -------------------------------------------------------------------------- */ void Material::onBeginningSolveStep(const AnalysisMethod & method) { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::onEndSolveStep(const AnalysisMethod & method) { ElementTypeMapArray::type_iterator it = this->element_filter.firstType(_all_dimensions, _not_ghost, _ek_not_defined); ElementTypeMapArray::type_iterator end = element_filter.lastType(_all_dimensions, _not_ghost, _ek_not_defined); for(; it != end; ++it) { this->updateEnergies(*it, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDamageIteration() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::onDamageUpdate() { ElementTypeMapArray::type_iterator it = this->element_filter.firstType(_all_dimensions, _not_ghost, _ek_not_defined); ElementTypeMapArray::type_iterator end = element_filter.lastType(_all_dimensions, _not_ghost, _ek_not_defined); for(; it != end; ++it) { this->updateEnergiesAfterDamage(*it, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDump(){ if(this->isFiniteDeformation()) this->computeAllCauchyStresses(_not_ghost); } /* -------------------------------------------------------------------------- */ void Material::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); std::string type = getID().substr(getID().find_last_of(":") + 1); stream << space << "Material " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } -/* -------------------------------------------------------------------------- */ -inline ElementTypeMap Material::getInternalDataPerElem(const ID & id, - const ElementKind & element_kind, - const ID & fe_engine_id) const { - - std::map *>::const_iterator internal_array = - internal_vectors_real.find(this->getID()+":"+id); - - if (internal_array == internal_vectors_real.end() || - internal_array->second->getElementKind() != element_kind) - AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); - - InternalField & internal = *internal_array->second; - InternalField::type_iterator it = internal.firstType(internal.getSpatialDimension(), - _not_ghost, element_kind); - InternalField::type_iterator last_type = internal.lastType(internal.getSpatialDimension(), - _not_ghost, element_kind); - - ElementTypeMap res; - for(; it != last_type; ++it) { - UInt nb_quadrature_points = 0; - nb_quadrature_points = model->getFEEngine(fe_engine_id).getNbIntegrationPoints(*it); - - res(*it) = internal.getNbComponent() * nb_quadrature_points; - } - return res; -} - -/* -------------------------------------------------------------------------- */ -void Material::flattenInternal(const std::string & field_id, - ElementTypeMapArray & internal_flat, - const GhostType ghost_type, - ElementKind element_kind) const { - this->flattenInternalIntern(field_id, internal_flat, - this->spatial_dimension, - ghost_type, element_kind); -} - -/* -------------------------------------------------------------------------- */ -void Material::flattenInternalIntern(const std::string & field_id, - ElementTypeMapArray & internal_flat, - UInt spatial_dimension, - const GhostType ghost_type, - ElementKind element_kind, - const ElementTypeMapArray * element_filter, - const Mesh * mesh) const { - typedef ElementTypeMapArray::type_iterator iterator; - - if(element_filter == NULL) element_filter = &(this->element_filter); - if(mesh == NULL) mesh = &(this->model->mesh); - - iterator tit = mesh->firstType(spatial_dimension, - ghost_type, - element_kind); - iterator end = mesh->lastType(spatial_dimension, - ghost_type, - element_kind); - - std::map *>::const_iterator internal_array = - internal_vectors_real.find(this->getID()+":"+field_id); - - if (!(internal_array == internal_vectors_real.end() || - internal_array->second->getElementKind() != element_kind)) { - - InternalField & internal = *internal_array->second; - - // number of data per quadrature point - UInt nb_data_per_quad = internal.getNbComponent(); - - for (; tit != end; ++tit) { - ElementType type = *tit; - // number of quadrature points per elem - UInt nb_quad_per_elem = this->fem->getNbIntegrationPoints(type); - // total number of elements for a given type - UInt nb_element = mesh->getNbElement(type,ghost_type); - - if (!internal_flat.exists(type,ghost_type)) { - internal_flat.alloc(nb_element * nb_quad_per_elem, - nb_data_per_quad, - type, - ghost_type); - } - - try { - __attribute__((unused)) const Array & src_vect - = this->getArray(field_id, type, ghost_type); - } catch(debug::Exception & e) { - continue; - } - - const Array & src_vect = this->getArray(field_id, type, ghost_type); - const Array & filter = (*element_filter)(type, ghost_type); - - // number of filtered elements - UInt nb_element_src = filter.getSize(); - - /// UInt nb_data_per_quad = src_vect.getNbComponent(); - - - if (nb_element_src == 0) continue; - nb_quad_per_elem = (src_vect.getSize() / nb_element_src); - - // number of data per element - UInt nb_data = nb_quad_per_elem * src_vect.getNbComponent(); - - Array & dst_vect = internal_flat(type,ghost_type); - dst_vect.resize(nb_element*nb_quad_per_elem); - - Array::const_scalar_iterator it = filter.begin(); - Array::const_scalar_iterator end = filter.end(); - Array::const_vector_iterator it_src = - src_vect.begin_reinterpret(nb_data, nb_element_src); - - Array::vector_iterator it_dst = - dst_vect.begin_reinterpret(nb_data, nb_element); - - for (; it != end ; ++it,++it_src) { - it_dst[*it] = *it_src; - } - } - } -}; - /* -------------------------------------------------------------------------- */ /// extrapolate internal values void Material::extrapolateInternal(const ID & id, const Element & element, const Matrix & point, Matrix & extrapolated) { - if (this->isInternal(id, element.kind)) { + if (this->isInternal(id, element.kind)) { UInt nb_element = this->element_filter(element.type, element.ghost_type).getSize(); const ID name = this->getID() + ":" + id; UInt nb_quads = this->internal_vectors_real[name]->getFEEngine().getNbIntegrationPoints(element.type, element.ghost_type); const Array & internal = this->getArray(id, element.type, element.ghost_type); UInt nb_component = internal.getNbComponent(); Array::const_matrix_iterator internal_it = internal.begin_reinterpret(nb_component, nb_quads, nb_element); Element local_element = this->convertToLocalElement(element); /// instead of really extrapolating, here the value of the first GP /// is copied into the result vector. This works only for linear /// elements /// @todo extrapolate!!!! AKANTU_DEBUG_WARNING("This is a fix, values are not truly extrapolated"); const Matrix & values = internal_it[local_element.element]; UInt index = 0; Vector tmp(nb_component); for (UInt j = 0; j < values.cols(); ++j) { tmp = values(j); if (tmp.norm() > 0) { index = j; break; } } for (UInt i = 0; i < extrapolated.size(); ++i) { extrapolated(i) = values(index); } } else { Matrix default_values(extrapolated.rows(), extrapolated.cols(), 0.); extrapolated = default_values; } } /* -------------------------------------------------------------------------- */ void Material::applyEigenGradU(const Matrix & prescribed_eigen_grad_u, const GhostType ghost_type) { ElementTypeMapArray::type_iterator it = this->element_filter.firstType(_all_dimensions, _not_ghost, _ek_not_defined); ElementTypeMapArray::type_iterator end = element_filter.lastType(_all_dimensions, _not_ghost, _ek_not_defined); for(; it != end; ++it) { ElementType type = *it; if (!element_filter(type, ghost_type).getSize()) continue; Array::matrix_iterator eigen_it = this->eigengradu(type, ghost_type).begin(spatial_dimension, spatial_dimension); Array::matrix_iterator eigen_end = this->eigengradu(type, ghost_type).end(spatial_dimension, spatial_dimension); for(; eigen_it != eigen_end; ++eigen_it) { Matrix & current_eigengradu = *eigen_it; current_eigengradu = prescribed_eigen_grad_u; } } } __END_AKANTU__ diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh index 46b773b6b..39f512864 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,640 +1,633 @@ /** * @file material.hh * * @author Marco Vocialta * @author Nicolas Richart * @author Daniel Pino Muñoz * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Mother class for all materials * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "aka_voigthelper.hh" #include "parser.hh" #include "parsable.hh" #include "data_accessor.hh" #include "internal_field.hh" #include "random_internal_field.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_HH__ #define __AKANTU_MATERIAL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Model; class SolidMechanicsModel; } __BEGIN_AKANTU__ /** * Interface of all materials * Prerequisites for a new material * - inherit from this class * - implement the following methods: * \code * virtual Real getStableTimeStep(Real h, const Element & element = ElementNull); * * virtual void computeStress(ElementType el_type, * GhostType ghost_type = _not_ghost); * * virtual void computeTangentStiffness(const ElementType & el_type, * Array & tangent_matrix, * GhostType ghost_type = _not_ghost); * \endcode * */ class Material : public Memory, public DataAccessor, public Parsable, public MeshEventHandler, protected SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: #if __cplusplus > 199711L Material(const Material & mat) = delete; Material & operator=(const Material & mat) = delete; #endif /// Initialize material with defaults Material(SolidMechanicsModel & model, const ID & id = ""); /// Initialize material with custom mesh & fe_engine Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); /// Destructor virtual ~Material(); protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Function that materials can/should reimplement */ /* ------------------------------------------------------------------------ */ protected: /// constitutive law virtual void computeStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the tangent stiffness matrix virtual void computeTangentModuli(__attribute__((unused)) const ElementType & el_type, __attribute__((unused)) Array & tangent_matrix, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the potential energy virtual void computePotentialEnergy(ElementType el_type, GhostType ghost_type = _not_ghost); /// compute the potential energy for an element virtual void computePotentialEnergyByElement(__attribute__((unused)) ElementType type, __attribute__((unused)) UInt index, __attribute__((unused)) Vector & epot_on_quad_points) { AKANTU_DEBUG_TO_IMPLEMENT(); } virtual void updateEnergies(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) { } virtual void updateEnergiesAfterDamage(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} /// set the material to steady state (to be implemented for materials that need it) virtual void setToSteadyState(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) { } /// function called to update the internal parameters when the modifiable /// parameters are modified virtual void updateInternalParameters() {} public: /// extrapolate internal values virtual void extrapolateInternal(const ID & id, const Element & element, const Matrix & points, Matrix & extrapolated); /// compute the p-wave speed in the material virtual Real getPushWaveSpeed(const Element & element) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the s-wave speed in the material virtual Real getShearWaveSpeed(const Element & element) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// get a material celerity to compute the stable time step (default: is the push wave speed) virtual Real getCelerity(const Element & element) const { return getPushWaveSpeed(element); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template void registerInternal(__attribute__((unused)) InternalField & vect) { AKANTU_DEBUG_TO_IMPLEMENT(); } template void unregisterInternal(__attribute__((unused)) InternalField & vect) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// initialize the material computed parameter virtual void initMaterial(); /// compute the residual for this material virtual void updateResidual(GhostType ghost_type = _not_ghost); /// assemble the residual for this material virtual void assembleResidual(GhostType ghost_type); /// save the stress in the previous_stress if needed virtual void savePreviousState(); /// compute the stresses for this material virtual void computeAllStresses(GhostType ghost_type = _not_ghost); virtual void computeAllStressesFromTangentModuli(GhostType ghost_type = _not_ghost); virtual void computeAllCauchyStresses(GhostType ghost_type = _not_ghost); /// set material to steady state void setToSteadyState(GhostType ghost_type = _not_ghost); /// compute the stiffness matrix virtual void assembleStiffnessMatrix(GhostType ghost_type); /// add an element to the local mesh filter inline UInt addElement(const ElementType & type, UInt element, const GhostType & ghost_type); /// add many elements at once void addElements(const Array & elements_to_add); /// remove many element at once void removeElements(const Array & elements_to_remove); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points */ void interpolateStress(ElementTypeMapArray & result, const GhostType ghost_type = _not_ghost); /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points and store the * results per facet */ void interpolateStressOnFacets(ElementTypeMapArray & result, ElementTypeMapArray & by_elem_result, const GhostType ghost_type = _not_ghost); /** * function to initialize the elemental field interpolation * function by inverting the quadrature points' coordinates */ void initElementalFieldInterpolation(const ElementTypeMapArray & interpolation_points_coordinates); /* ------------------------------------------------------------------------ */ /* Common part */ /* ------------------------------------------------------------------------ */ protected: /* ------------------------------------------------------------------------ */ inline UInt getTangentStiffnessVoigtSize(UInt spatial_dimension) const; /// compute the potential energy by element void computePotentialEnergyByElements(); /// resize the intenals arrays virtual void resizeInternals(); /* ------------------------------------------------------------------------ */ /* Finite deformation functions */ /* This functions area implementing what is described in the paper of Bathe */ /* et al, in IJNME, Finite Element Formulations For Large Deformation */ /* Dynamic Analysis, Vol 9, 353-386, 1975 */ /* ------------------------------------------------------------------------ */ protected: /// assemble the residual template void assembleResidual(GhostType ghost_type); /// Computation of Cauchy stress tensor in the case of finite deformation from /// the 2nd Piola-Kirchhoff for a given element type template void computeCauchyStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost); /// Computation the Cauchy stress the 2nd Piola-Kirchhoff and the deformation /// gradient template inline void computeCauchyStressOnQuad(const Matrix & F, const Matrix & S, Matrix & cauchy, const Real & C33 = 1.0) const; template void computeAllStressesFromTangentModuli(const ElementType & type, GhostType ghost_type); template void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// assembling in finite deformation template void assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type); template void assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type); /// Size of the Stress matrix for the case of finite deformation see: Bathe et /// al, IJNME, Vol 9, 353-386, 1975 inline UInt getCauchyStressMatrixSize(UInt spatial_dimension) const; /// Sets the stress matrix according to Bathe et al, IJNME, Vol 9, 353-386, 1975 template inline void setCauchyStressMatrix(const Matrix & S_t, Matrix & sigma); /// write the stress tensor in the Voigt notation. template inline void setCauchyStressArray(const Matrix & S_t, Matrix & sigma_voight); /* ------------------------------------------------------------------------ */ /* Conversion functions */ /* ------------------------------------------------------------------------ */ public: template static inline void gradUToF (const Matrix & grad_u, Matrix & F); static inline void rightCauchy(const Matrix & F, Matrix & C); static inline void leftCauchy (const Matrix & F, Matrix & B); template static inline void gradUToEpsilon(const Matrix & grad_u, Matrix & epsilon); template static inline void gradUToGreenStrain(const Matrix & grad_u, Matrix & epsilon); static inline Real stressToVonMises(const Matrix & stress); protected: /// converts global element to local element inline Element convertToLocalElement(const Element & global_element) const; /// converts local element to global element inline Element convertToGlobalElement(const Element & local_element) const; /// converts global quadrature point to local quadrature point inline IntegrationPoint convertToLocalPoint(const IntegrationPoint & global_point) const; /// converts local quadrature point to global quadrature point inline IntegrationPoint convertToGlobalPoint(const IntegrationPoint & local_point) const; /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: virtual inline UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const; virtual inline void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const; virtual inline void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag); template inline void packElementDataHelper(const ElementTypeMapArray & data_to_pack, CommunicationBuffer & buffer, const Array & elements, const ID & fem_id = ID()) const; template inline void unpackElementDataHelper(ElementTypeMapArray & data_to_unpack, CommunicationBuffer & buffer, const Array & elements, const ID & fem_id = ID()); /* ------------------------------------------------------------------------ */ /* MeshEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ virtual void onNodesAdded( __attribute__((unused)) const Array & nodes_list, __attribute__((unused)) const NewNodesEvent & event) {}; virtual void onNodesRemoved( __attribute__((unused)) const Array & nodes_list, __attribute__((unused)) const Array & new_numbering, __attribute__((unused)) const RemovedNodesEvent & event) {}; virtual void onElementsAdded(const Array & element_list, const NewElementsEvent & event); virtual void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event); + virtual void onElementsChanged(__attribute__((unused)) const Array & old_elements_list, + __attribute__((unused)) const Array & new_elements_list, + __attribute__((unused)) const ElementTypeMapArray & new_numbering, + __attribute__((unused)) const ChangedElementsEvent & event) {}; + /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void onBeginningSolveStep(const AnalysisMethod & method); virtual void onEndSolveStep(const AnalysisMethod & method); virtual void onDamageIteration(); virtual void onDamageUpdate(); virtual void onDump(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Name, name, const std::string &); AKANTU_GET_MACRO(Model, *model, const SolidMechanicsModel &) AKANTU_GET_MACRO(ID, Memory::getID(), const ID &); AKANTU_GET_MACRO(Rho, rho, Real); AKANTU_SET_MACRO(Rho, rho, Real); AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// return the potential energy for the subset of elements contained by the material Real getPotentialEnergy(); /// return the potential energy for the provided element Real getPotentialEnergy(ElementType & type, UInt index); /// return the energy (identified by id) for the subset of elements contained by the material virtual Real getEnergy(std::string energy_id); /// return the energy (identified by id) for the provided element virtual Real getEnergy(std::string energy_id, ElementType type, UInt index); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementFilter, element_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(GradU, gradu, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PotentialEnergy, potential_energy, Real); AKANTU_GET_MACRO(GradU, gradu, const ElementTypeMapArray &); AKANTU_GET_MACRO(Stress, stress, const ElementTypeMapArray &); AKANTU_GET_MACRO(ElementFilter, element_filter, const ElementTypeMapArray &); AKANTU_GET_MACRO(FEEngine, *fem, FEEngine &); bool isNonLocal() const { return is_non_local; } template const Array & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; template Array & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost); template const InternalField & getInternal(const ID & id) const; template InternalField & getInternal(const ID & id); + template inline bool isInternal(const ID & id, const ElementKind & element_kind) const; - virtual ElementTypeMap getInternalDataPerElem(const ID & id, - const ElementKind & element_kind, - const ID & fe_engine_id = "") const; + + template + ElementTypeMap getInternalDataPerElem(const ID & id, + const ElementKind & element_kind) const; bool isFiniteDeformation() const { return finite_deformation; } bool isInelasticDeformation() const { return inelastic_deformation; } template inline void setParam(const ID & param, T value); template inline const T & getParam(const ID & param) const; - virtual void flattenInternal(const std::string & field_id, - ElementTypeMapArray & internal_flat, - const GhostType ghost_type = _not_ghost, - ElementKind element_kind = _ek_not_defined) const; + template + void flattenInternal(const std::string & field_id, + ElementTypeMapArray & internal_flat, + const GhostType ghost_type = _not_ghost, + ElementKind element_kind = _ek_not_defined) const; /// apply a constant eigengrad_u everywhere in the material virtual void applyEigenGradU(const Matrix & prescribed_eigen_grad_u, const GhostType = _not_ghost); -protected: - /// internal variation of the flatten function that is more flexible and can - /// be used by inherited materials to change some behavior - virtual void flattenInternalIntern(const std::string & field_id, - ElementTypeMapArray & internal_flat, - UInt spatial_dimension, - const GhostType ghost_type, - ElementKind element_kind, - const ElementTypeMapArray * element_filter = NULL, - const Mesh * mesh = NULL) const; - protected: bool isInit() const { return is_init; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// boolean to know if the material has been initialized bool is_init; std::map *> internal_vectors_real; std::map *> internal_vectors_uint; std::map *> internal_vectors_bool; protected: /// Link to the fem object in the model FEEngine * fem; /// Finite deformation bool finite_deformation; /// Finite deformation bool inelastic_deformation; /// material name std::string name; /// The model to witch the material belong SolidMechanicsModel * model; /// density : rho Real rho; /// spatial dimension UInt spatial_dimension; /// list of element handled by the material ElementTypeMapArray element_filter; /// stresses arrays ordered by element types InternalField stress; /// eigengrad_u arrays ordered by element types InternalField eigengradu; /// grad_u arrays ordered by element types InternalField gradu; /// Green Lagrange strain (Finite deformation) InternalField green_strain; /// Second Piola-Kirchhoff stress tensor arrays ordered by element types (Finite deformation) InternalField piola_kirchhoff_2; /// potential energy by element InternalField potential_energy; /// tell if using in non local mode or not bool is_non_local; /// tell if the material need the previous stress state bool use_previous_stress; /// tell if the material need the previous strain state bool use_previous_gradu; /// elemental field interpolation coordinates InternalField interpolation_inverse_coordinates; /// elemental field interpolation points InternalField interpolation_points_matrices; /// vector that contains the names of all the internals that need to /// be transferred when material interfaces move std::vector internals_to_transfer; }; -/* -------------------------------------------------------------------------- */ -/* inline functions */ -/* -------------------------------------------------------------------------- */ - -#include "material_inline_impl.cc" - /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Material & _this) { _this.printself(stream); return stream; } __END_AKANTU__ +#include "material_inline_impl.cc" + #include "internal_field_tmpl.hh" #include "random_internal_field_tmpl.hh" /* -------------------------------------------------------------------------- */ /* Auto loop */ /* -------------------------------------------------------------------------- */ /// This can be used to automatically write the loop on quadrature points in /// functions such as computeStress. This macro in addition to write the loop /// provides two tensors (matrices) sigma and grad_u #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type) \ Array::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type).begin(this->spatial_dimension, \ this->spatial_dimension); \ Array::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type).end(this->spatial_dimension, \ this->spatial_dimension); \ \ this->stress(el_type, \ ghost_type).resize(this->gradu(el_type, \ ghost_type).getSize()); \ \ Array::iterator< Matrix > stress_it = \ this->stress(el_type, ghost_type).begin(this->spatial_dimension, \ this->spatial_dimension); \ \ if(this->isFiniteDeformation()){ \ this->piola_kirchhoff_2(el_type, \ ghost_type).resize(this->gradu(el_type, \ ghost_type).getSize()); \ stress_it = \ this->piola_kirchhoff_2(el_type, \ ghost_type).begin(this->spatial_dimension, \ this->spatial_dimension); \ } \ \ for(;gradu_it != gradu_end; ++gradu_it, ++stress_it) { \ Matrix & __attribute__((unused)) grad_u = *gradu_it; \ Matrix & __attribute__((unused)) sigma = *stress_it #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END \ } \ /// This can be used to automatically write the loop on quadrature points in /// functions such as computeTangentModuli. This macro in addition to write the /// loop provides two tensors (matrices) sigma_tensor, grad_u, and a matrix /// where the elemental tangent moduli should be stored in Voigt Notation #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_mat) \ Array::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type).begin(this->spatial_dimension, \ this->spatial_dimension); \ Array::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type).end(this->spatial_dimension, \ this->spatial_dimension); \ Array::matrix_iterator sigma_it = \ this->stress(el_type, ghost_type).begin(this->spatial_dimension, \ this->spatial_dimension); \ \ tangent_mat.resize(this->gradu(el_type, ghost_type).getSize()); \ \ UInt tangent_size = \ this->getTangentStiffnessVoigtSize(this->spatial_dimension); \ Array::matrix_iterator tangent_it = \ tangent_mat.begin(tangent_size, \ tangent_size); \ \ for(;gradu_it != gradu_end; ++gradu_it, ++sigma_it, ++tangent_it) { \ Matrix & __attribute__((unused)) grad_u = *gradu_it; \ Matrix & __attribute__((unused)) sigma_tensor = *sigma_it; \ Matrix & tangent = *tangent_it #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END \ } \ /* -------------------------------------------------------------------------- */ #define INSTANTIATE_MATERIAL(mat_name) \ template class mat_name<1>; \ template class mat_name<2>; \ template class mat_name<3> #endif /* __AKANTU_MATERIAL_HH__ */ diff --git a/src/model/solid_mechanics/material_inline_impl.cc b/src/model/solid_mechanics/material_inline_impl.cc index 041e4b0c5..e9408ba69 100644 --- a/src/model/solid_mechanics/material_inline_impl.cc +++ b/src/model/solid_mechanics/material_inline_impl.cc @@ -1,341 +1,461 @@ /** * @file material_inline_impl.cc * * @author Marco Vocialta * @author Nicolas Richart * @author Daniel Pino Muñoz * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Implementation of the inline functions of the class material * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 . * */ -__END_AKANTU__ - +/* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" -#include +/* -------------------------------------------------------------------------- */ -__BEGIN_AKANTU__ +#ifndef __AKANTU_MATERIAL_INLINE_IMPL_CC__ +#define __AKANTU_MATERIAL_INLINE_IMPL_CC__ +__BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -inline UInt Material::addElement(const ElementType & type, - UInt element, +inline UInt Material::addElement(const ElementType & type, UInt element, const GhostType & ghost_type) { - Array & el_filter = element_filter(type, ghost_type); + Array & el_filter = this->element_filter(type, ghost_type); el_filter.push_back(element); - return el_filter.getSize()-1; + return el_filter.getSize() - 1; } /* -------------------------------------------------------------------------- */ inline UInt Material::getTangentStiffnessVoigtSize(UInt dim) const { return (dim * (dim - 1) / 2 + dim); } /* -------------------------------------------------------------------------- */ inline UInt Material::getCauchyStressMatrixSize(UInt dim) const { return (dim * dim); } /* -------------------------------------------------------------------------- */ -template -inline void Material::gradUToF(const Matrix & grad_u, - Matrix & 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."); +template +inline void Material::gradUToF(const Matrix & grad_u, Matrix & 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 +template inline void Material::computeCauchyStressOnQuad(const Matrix & F, const Matrix & piola, Matrix & sigma, - const Real & C33 ) const { + const Real & C33) const { Real J = F.det() * sqrt(C33); Matrix F_S(dim, dim); F_S.mul(F, piola); - Real constant = J ? 1./J : 0; + Real constant = J ? 1. / J : 0; sigma.mul(F_S, F, constant); } /* -------------------------------------------------------------------------- */ -inline void Material::rightCauchy(const Matrix & F, - Matrix & C) { +inline void Material::rightCauchy(const Matrix & F, Matrix & C) { C.mul(F, F); } /* -------------------------------------------------------------------------- */ -inline void Material::leftCauchy(const Matrix & F, - Matrix & B) { +inline void Material::leftCauchy(const Matrix & F, Matrix & B) { B.mul(F, F); } /* -------------------------------------------------------------------------- */ -template +template inline void Material::gradUToEpsilon(const Matrix & grad_u, Matrix & 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)); + epsilon(i, j) = 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ -template +template inline void Material::gradUToGreenStrain(const Matrix & grad_u, Matrix & epsilon) { epsilon.mul(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 & stress) { // compute deviatoric stress UInt dim = stress.cols(); - Matrix deviatoric_stress = Matrix::eye(dim, -1. * stress.trace() / 3.); + Matrix deviatoric_stress = + Matrix::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); + deviatoric_stress(i, j) += stress(i, j); // return Von Mises stress return std::sqrt(3. * deviatoric_stress.doubleDot(deviatoric_stress) / 2.); } /* ---------------------------------------------------------------------------*/ -template -inline void Material::setCauchyStressArray(const Matrix & S_t, Matrix & sigma_voight) { +template +inline void Material::setCauchyStressArray(const Matrix & S_t, + Matrix & sigma_voight) { AKANTU_DEBUG_IN(); sigma_voight.clear(); - //see Finite ekement formulations for large deformation dynamic analysis, Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau + // see Finite ekement 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 + 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 = 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); + for (UInt i = 2; i < dim; ++i) // term s13 in 3D + sigma_voight(dim + i, 0) = S_t(0, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -template -inline void Material::setCauchyStressMatrix(const Matrix & S_t, Matrix & sigma) { +template +inline void Material::setCauchyStressMatrix(const Matrix & S_t, + Matrix & 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 { +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 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); + "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); + UInt le = this->model->getMaterialLocalNumbering( + global_element.type, global_element.ghost_type)(ge); - Element tmp_quad(global_element.type, - le, - global_element.ghost_type, + Element tmp_quad(global_element.type, le, global_element.ghost_type, global_element.kind); return tmp_quad; } /* -------------------------------------------------------------------------- */ -inline Element Material::convertToGlobalElement(const Element & local_element) const { +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); + UInt ge = + this->element_filter(local_element.type, local_element.ghost_type)(le); - Element tmp_quad(local_element.type, - ge, - local_element.ghost_type, + Element tmp_quad(local_element.type, ge, local_element.ghost_type, local_element.kind); return tmp_quad; } /* -------------------------------------------------------------------------- */ -inline IntegrationPoint Material::convertToLocalPoint(const IntegrationPoint & global_point) const { +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(global_point)); + Element el = + this->convertToLocalElement(static_cast(global_point)); IntegrationPoint tmp_quad(el, global_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ -inline IntegrationPoint Material::convertToGlobalPoint(const IntegrationPoint & local_point) const { +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(local_point)); + Element el = + this->convertToGlobalElement(static_cast(local_point)); IntegrationPoint tmp_quad(el, local_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline UInt Material::getNbDataForElements(const Array & elements, SynchronizationTag tag) const { - if(tag == _gst_smm_stress) { - return (this->isFiniteDeformation() ? 3 : 1) * spatial_dimension * spatial_dimension * - sizeof(Real) * this->getModel().getNbIntegrationPoints(elements); + 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::packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const { - if(tag == _gst_smm_stress) { - if(this->isFiniteDeformation()) { + 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::unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) { - if(tag == _gst_smm_stress) { - if(this->isFiniteDeformation()) { + if (tag == _gst_smm_stress) { + if (this->isFiniteDeformation()) { unpackElementDataHelper(piola_kirchhoff_2, buffer, elements); unpackElementDataHelper(gradu, buffer, elements); } unpackElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ template inline const T & Material::getParam(const ID & param) const { try { return get(param); } catch (...) { - AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); + AKANTU_EXCEPTION("No parameter " << param << " in the material " + << getID()); } } /* -------------------------------------------------------------------------- */ template inline void Material::setParam(const ID & param, T value) { try { set(param, value); - } catch(...) { - AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); + } catch (...) { + AKANTU_EXCEPTION("No parameter " << param << " in the material " + << getID()); } updateInternalParameters(); } /* -------------------------------------------------------------------------- */ -template -inline void Material::packElementDataHelper(const ElementTypeMapArray & data_to_pack, - CommunicationBuffer & buffer, - const Array & elements, - const ID & fem_id) const { +template +inline void Material::packElementDataHelper( + const ElementTypeMapArray & data_to_pack, CommunicationBuffer & buffer, + const Array & elements, const ID & fem_id) const { DataAccessor::packElementalDataHelper(data_to_pack, buffer, elements, true, model->getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ -template -inline void Material::unpackElementDataHelper(ElementTypeMapArray & data_to_unpack, - CommunicationBuffer & buffer, - const Array & elements, - const ID & fem_id) { - DataAccessor::unpackElementalDataHelper(data_to_unpack, buffer, elements, true, - model->getFEEngine(fem_id)); +template +inline void Material::unpackElementDataHelper( + ElementTypeMapArray & data_to_unpack, CommunicationBuffer & buffer, + const Array & elements, const ID & fem_id) { + DataAccessor::unpackElementalDataHelper(data_to_unpack, buffer, elements, + true, model->getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ -template<> inline void Material::registerInternal(InternalField & vect) { +template <> +inline void Material::registerInternal(InternalField & vect) { internal_vectors_real[vect.getID()] = &vect; } -template<> inline void Material::registerInternal(InternalField & vect) { +template <> +inline void Material::registerInternal(InternalField & vect) { internal_vectors_uint[vect.getID()] = &vect; } -template<> inline void Material::registerInternal(InternalField & vect) { +template <> +inline void Material::registerInternal(InternalField & vect) { internal_vectors_bool[vect.getID()] = &vect; } /* -------------------------------------------------------------------------- */ -template<> inline void Material::unregisterInternal(InternalField & vect) { +template <> +inline void Material::unregisterInternal(InternalField & vect) { internal_vectors_real.erase(vect.getID()); } -template<> inline void Material::unregisterInternal(InternalField & vect) { +template <> +inline void Material::unregisterInternal(InternalField & vect) { internal_vectors_uint.erase(vect.getID()); } -template<> inline void Material::unregisterInternal(InternalField & vect) { +template <> +inline void Material::unregisterInternal(InternalField & vect) { internal_vectors_bool.erase(vect.getID()); } /* -------------------------------------------------------------------------- */ -inline bool Material::isInternal(const ID & id, const ElementKind & element_kind) const { +template +inline bool Material::isInternal(const ID & id, + const ElementKind & element_kind) const { + AKANTU_DEBUG_TO_IMPLEMENT(); +} +template <> +inline bool Material::isInternal(const ID & id, + const ElementKind & element_kind) const { std::map *>::const_iterator internal_array = - internal_vectors_real.find(this->getID()+":"+id); + internal_vectors_real.find(this->getID() + ":" + id); if (internal_array == internal_vectors_real.end() || - internal_array->second->getElementKind() != element_kind) return false; + internal_array->second->getElementKind() != element_kind) + return false; return true; } + +/* -------------------------------------------------------------------------- */ +template +inline ElementTypeMap +Material::getInternalDataPerElem(const ID & field_id, + const ElementKind & element_kind) const { + + if (!this->template isInternal(field_id, element_kind)) + AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " + << this->name); + + const InternalField & internal_field = + this->template getInternal(field_id); + const FEEngine & fe_engine = internal_field.getFEEngine(); + UInt nb_data_per_quad = internal_field.getNbComponent(); + + ElementTypeMap res; + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { + + typedef typename InternalField::type_iterator 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 +void Material::flattenInternal(const std::string & field_id, + ElementTypeMapArray & internal_flat, + const GhostType ghost_type, + ElementKind element_kind) const { + + if (!this->template isInternal(field_id, element_kind)) + AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " + << this->name); + + const InternalField & internal_field = + this->template getInternal(field_id); + + const FEEngine & fe_engine = internal_field.getFEEngine(); + const Mesh & mesh = fe_engine.getMesh(); + + typedef typename InternalField::filter_type_iterator 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 & src_vect = internal_field(type, ghost_type); + const Array & 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.getSize(); + // 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 & dst_vect = internal_flat(type, ghost_type); + dst_vect.resize(nb_element_dst * nb_quad_per_elem); + + Array::const_scalar_iterator it = filter.begin(); + Array::const_scalar_iterator end = filter.end(); + + Array::const_vector_iterator it_src = + src_vect.begin_reinterpret(nb_data, nb_element_src); + Array::vector_iterator it_dst = + dst_vect.begin_reinterpret(nb_data, nb_element_dst); + + for (; it != end; ++it, ++it_src) { + it_dst[*it] = *it_src; + } + } +} + +__END_AKANTU__ + +#endif /* __AKANTU_MATERIAL_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/internal_field.hh b/src/model/solid_mechanics/materials/internal_field.hh index fb359f48b..f8e4666d1 100644 --- a/src/model/solid_mechanics/materials/internal_field.hh +++ b/src/model/solid_mechanics/materials/internal_field.hh @@ -1,221 +1,256 @@ /** * @file internal_field.hh * * @author Nicolas Richart * * @date creation: Wed Nov 13 2013 * @date last modification: Tue Sep 02 2014 * * @brief Material internal properties * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_type_map.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTERNAL_FIELD_HH__ #define __AKANTU_INTERNAL_FIELD_HH__ __BEGIN_AKANTU__ class Material; class FEEngine; /** * class for the internal fields of materials * to store values for each quadrature */ -template -class InternalField : public ElementTypeMapArray { +template class InternalField : public ElementTypeMapArray { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: InternalField(const ID & id, Material & material); virtual ~InternalField(); /// This constructor is only here to let cohesive elements compile - InternalField(const ID & id, - Material & material, - FEEngine & fem, - const ElementTypeMapArray & element_filter); + InternalField(const ID & id, Material & material, FEEngine & fem, + const ElementTypeMapArray & element_filter); /// More general constructor - InternalField(const ID & id, - Material & material, - UInt dim, - FEEngine & fem, - const ElementTypeMapArray & element_filter); + InternalField(const ID & id, Material & material, UInt dim, FEEngine & fem, + const ElementTypeMapArray & element_filter); InternalField(const ID & id, const InternalField & other); private: - InternalField operator=(__attribute__((unused)) const InternalField & other) {}; + InternalField operator=(__attribute__((unused)) + const InternalField & other){}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - /// function to reset the FEEngine for the internal field virtual void setFEEngine(FEEngine & fe_engine); /// function to reset the element kind for the internal virtual void setElementKind(ElementKind element_kind); /// initialize the field to a given number of component virtual void initialize(UInt nb_component); /// activate the history of this field virtual void initializeHistory(); /// resize the arrays and set the new element to 0 virtual void resize(); /// set the field to a given value v virtual void setDefaultValue(const T & v); /// reset all the fields to the default value virtual void reset(); /// save the current values in the history virtual void saveCurrentValues(); /// remove the quadrature points corresponding to suppressed elements - virtual void removeIntegrationPoints(const ElementTypeMapArray & new_numbering); + virtual void + removeIntegrationPoints(const ElementTypeMapArray & new_numbering); /// print the content virtual void printself(std::ostream & stream, UInt indent = 0) const; /// get the default value inline operator T() const; - virtual FEEngine & getFEEngine() { - return *fem;} - ///AKANTU_GET_MACRO(FEEngine, *fem, FEEngine &); + virtual FEEngine & getFEEngine() { return *fem; } + + virtual const FEEngine & getFEEngine() const { return *fem; } + + /// AKANTU_GET_MACRO(FEEngine, *fem, FEEngine &); protected: /// initialize the arrays in the ElementTypeMapArray void internalInitialize(UInt nb_component); /// set the values for new internals virtual void setArrayValues(T * begin, T * end); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: + typedef typename ElementTypeMapArray::type_iterator type_iterator; + typedef typename ElementTypeMapArray::type_iterator filter_type_iterator; + + /// get the type iterator on all types contained in the internal field + type_iterator firstType(const GhostType & ghost_type = _not_ghost) const { + return ElementTypeMapArray::firstType(this->spatial_dimension, ghost_type, + this->element_kind); + } + + /// get the type iterator on the last type contained in the internal field + type_iterator lastType(const GhostType & ghost_type = _not_ghost) const { + return ElementTypeMapArray::lastType(this->spatial_dimension, ghost_type, + this->element_kind); + } + + /// get the type iterator on all types contained in the internal field + filter_type_iterator filterFirstType(const GhostType & ghost_type = _not_ghost) const { + return this->element_filter.firstType(this->spatial_dimension, ghost_type, + this->element_kind); + } + + /// get the type iterator on the last type contained in the internal field + filter_type_iterator filterLastType(const GhostType & ghost_type = _not_ghost) const { + return this->element_filter.lastType(this->spatial_dimension, ghost_type, + this->element_kind); + } + + /// get the array for a given type of the element_filter + const Array getFilter(const ElementType & type, + const GhostType & ghost_type = _not_ghost) const { + return this->element_filter(type, ghost_type); + } /// get the Array corresponding to the type en ghost_type specified - virtual Array & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost) { + virtual Array & operator()(const ElementType & type, + const GhostType & ghost_type = _not_ghost) { return ElementTypeMapArray::operator()(type, ghost_type); } - virtual const Array & operator()(const ElementType & type, const GhostType & ghost_type = _not_ghost) const { + virtual const Array & + operator()(const ElementType & type, + const GhostType & ghost_type = _not_ghost) const { return ElementTypeMapArray::operator()(type, ghost_type); } - virtual Array & previous(const ElementType & type, const GhostType & ghost_type = _not_ghost) { + virtual Array & previous(const ElementType & type, + const GhostType & ghost_type = _not_ghost) { AKANTU_DEBUG_ASSERT(previous_values != NULL, - "The history of the internal " << this->getID() - << " has not been activated"); + "The history of the internal " + << this->getID() << " has not been activated"); return this->previous_values->operator()(type, ghost_type); } - virtual const Array & previous(const ElementType & type, const GhostType & ghost_type = _not_ghost) const { + virtual const Array & + previous(const ElementType & type, + const GhostType & ghost_type = _not_ghost) const { AKANTU_DEBUG_ASSERT(previous_values != NULL, - "The history of the internal " << this->getID() - << " has not been activated"); + "The history of the internal " + << this->getID() << " has not been activated"); return this->previous_values->operator()(type, ghost_type); } - virtual InternalField & previous() { AKANTU_DEBUG_ASSERT(previous_values != NULL, - "The history of the internal " << this->getID() - << " has not been activated"); + "The history of the internal " + << this->getID() << " has not been activated"); return *(this->previous_values); } virtual const InternalField & previous() const { AKANTU_DEBUG_ASSERT(previous_values != NULL, - "The history of the internal " << this->getID() - << " has not been activated"); + "The history of the internal " + << this->getID() << " has not been activated"); return *(this->previous_values); } /// check if the history is used or not bool hasHistory() const { return (previous_values != NULL); } /// get the kind treated by the internal const ElementKind & getElementKind() const { return element_kind; } /// return the number of components UInt getNbComponent() const { return nb_component; } - /// return the spatial dimension corresponding to the internal element type loop filter + /// return the spatial dimension corresponding to the internal element type + /// loop filter UInt getSpatialDimension() const { return this->spatial_dimension; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the material for which this is an internal parameter Material & material; /// the fem containing the mesh and the element informations FEEngine * fem; /// Element filter if needed const ElementTypeMapArray & element_filter; /// default value T default_value; /// spatial dimension of the element to consider UInt spatial_dimension; /// ElementKind of the element to consider ElementKind element_kind; /// Number of component of the internal field UInt nb_component; /// Is the field initialized bool is_init; /// previous values InternalField * previous_values; }; /// standard output stream operator -template -inline std::ostream & operator <<(std::ostream & stream, const InternalField & _this) -{ +template +inline std::ostream & operator<<(std::ostream & stream, + const InternalField & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_INTERNAL_FIELD_HH__ */ diff --git a/src/model/solid_mechanics/materials/internal_field_tmpl.hh b/src/model/solid_mechanics/materials/internal_field_tmpl.hh index 72839fbb4..14ea5d42b 100644 --- a/src/model/solid_mechanics/materials/internal_field_tmpl.hh +++ b/src/model/solid_mechanics/materials/internal_field_tmpl.hh @@ -1,339 +1,320 @@ /** * @file internal_field_tmpl.hh * * @author Nicolas Richart * * @date creation: Wed Nov 13 2013 * @date last modification: Thu Jun 05 2014 * * @brief Material internal properties * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_INTERNAL_FIELD_TMPL_HH__ #define __AKANTU_INTERNAL_FIELD_TMPL_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -template -InternalField::InternalField(const ID & id, Material & material) : - ElementTypeMapArray(id, material.getID(), material.getMemoryID()), - material(material), - fem(&(material.getModel().getFEEngine())), - element_filter(material.getElementFilter()), - default_value(T()), - spatial_dimension(material.getModel().getSpatialDimension()), - element_kind(_ek_regular), - nb_component(0), - is_init(false), - previous_values(NULL) { -} +template +InternalField::InternalField(const ID & id, Material & material) + : ElementTypeMapArray(id, material.getID(), material.getMemoryID()), + material(material), fem(&(material.getModel().getFEEngine())), + element_filter(material.getElementFilter()), default_value(T()), + spatial_dimension(material.getModel().getSpatialDimension()), + element_kind(_ek_regular), nb_component(0), is_init(false), + previous_values(NULL) {} /* -------------------------------------------------------------------------- */ -template -InternalField::InternalField(const ID & id, - Material & material, - FEEngine & fem, - const ElementTypeMapArray & element_filter) : - ElementTypeMapArray(id, material.getID(), material.getMemoryID()), - material(material), - fem(&fem), - element_filter(element_filter), - default_value(T()), - spatial_dimension(material.getSpatialDimension()), - element_kind(_ek_regular), - nb_component(0), - is_init(false), - previous_values(NULL) { -} +template +InternalField::InternalField( + const ID & id, Material & material, FEEngine & fem, + const ElementTypeMapArray & element_filter) + : ElementTypeMapArray(id, material.getID(), material.getMemoryID()), + material(material), fem(&fem), element_filter(element_filter), + default_value(T()), spatial_dimension(material.getSpatialDimension()), + element_kind(_ek_regular), nb_component(0), is_init(false), + previous_values(NULL) {} /* -------------------------------------------------------------------------- */ -template -InternalField::InternalField(const ID & id, - Material & material, - UInt dim, - FEEngine & fem, - const ElementTypeMapArray & element_filter) : - ElementTypeMapArray(id, material.getID(), material.getMemoryID()), - material(material), - fem(&fem), - element_filter(element_filter), - default_value(T()), - spatial_dimension(dim), - element_kind(_ek_regular), - nb_component(0), - is_init(false), - previous_values(NULL) { -} +template +InternalField::InternalField( + const ID & id, Material & material, UInt dim, FEEngine & fem, + const ElementTypeMapArray & element_filter) + : ElementTypeMapArray(id, material.getID(), material.getMemoryID()), + material(material), fem(&fem), element_filter(element_filter), + default_value(T()), spatial_dimension(dim), element_kind(_ek_regular), + nb_component(0), is_init(false), previous_values(NULL) {} /* -------------------------------------------------------------------------- */ -template -InternalField::InternalField(const ID & id, const InternalField & other) : - ElementTypeMapArray(id, other.material.getID(), other.material.getMemoryID()), - material(other.material), - fem(other.fem), - element_filter(other.element_filter), - default_value(other.default_value), - spatial_dimension(other.spatial_dimension), - element_kind(other.element_kind), - nb_component(other.nb_component), - is_init(false), - previous_values(NULL) { - - AKANTU_DEBUG_ASSERT(other.is_init, "Cannot create a copy of a non initialized field"); +template +InternalField::InternalField(const ID & id, const InternalField & other) + : ElementTypeMapArray(id, other.material.getID(), + other.material.getMemoryID()), + material(other.material), fem(other.fem), + element_filter(other.element_filter), default_value(other.default_value), + spatial_dimension(other.spatial_dimension), + element_kind(other.element_kind), nb_component(other.nb_component), + is_init(false), previous_values(NULL) { + + AKANTU_DEBUG_ASSERT(other.is_init, + "Cannot create a copy of a non initialized field"); this->internalInitialize(this->nb_component); } - /* -------------------------------------------------------------------------- */ -template -InternalField::~InternalField() { - if(this->is_init) { +template InternalField::~InternalField() { + if (this->is_init) { this->material.unregisterInternal(*this); } delete previous_values; } /* -------------------------------------------------------------------------- */ -template -void InternalField::setFEEngine(FEEngine & fe_engine) { +template void InternalField::setFEEngine(FEEngine & fe_engine) { this->fem = &fe_engine; } /* -------------------------------------------------------------------------- */ -template +template void InternalField::setElementKind(ElementKind element_kind) { this->element_kind = element_kind; } /* -------------------------------------------------------------------------- */ -template -void InternalField::initialize(UInt nb_component) { +template void InternalField::initialize(UInt nb_component) { internalInitialize(nb_component); } /* -------------------------------------------------------------------------- */ -template -void InternalField::initializeHistory() { - if(!previous_values) +template void InternalField::initializeHistory() { + if (!previous_values) previous_values = new InternalField("previous_" + this->getID(), *this); } /* -------------------------------------------------------------------------- */ -template -void InternalField::resize() { - if(!this->is_init) return; +template void InternalField::resize() { + if (!this->is_init) + return; + + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { - for(UInt g = _not_ghost; g <= _ghost; ++g) { - GhostType gt = (GhostType) g; + filter_type_iterator it = this->filterFirstType(*gt); + filter_type_iterator end = this->filterLastType(*gt); - typename ElementTypeMapArray::type_iterator it - = element_filter.firstType(spatial_dimension, gt, element_kind); - typename ElementTypeMapArray::type_iterator end - = element_filter.lastType(spatial_dimension, gt, element_kind); - for(; it != end; ++it) { - UInt nb_element = element_filter(*it, gt).getSize(); + for (; it != end; ++it) { + UInt nb_element = this->element_filter(*it, *gt).getSize(); - UInt nb_quadrature_points = fem->getNbIntegrationPoints(*it, gt); + UInt nb_quadrature_points = this->fem->getNbIntegrationPoints(*it, *gt); UInt new_size = nb_element * nb_quadrature_points; UInt old_size = 0; Array * vect = NULL; - if(this->exists(*it, gt)) { - vect = &(this->operator()(*it, gt)); - old_size = vect->getSize(); - vect->resize(new_size); + if (this->exists(*it, *gt)) { + vect = &(this->operator()(*it, *gt)); + old_size = vect->getSize(); + vect->resize(new_size); } else { - vect = &(this->alloc(nb_element * nb_quadrature_points, nb_component, *it, gt)); + vect = &(this->alloc(nb_element * nb_quadrature_points, nb_component, + *it, *gt)); } this->setArrayValues(vect->storage() + old_size * vect->getNbComponent(), - vect->storage() + new_size * vect->getNbComponent()); + vect->storage() + new_size * vect->getNbComponent()); } } } /* -------------------------------------------------------------------------- */ -template -void InternalField::setDefaultValue(const T & value) { +template void InternalField::setDefaultValue(const T & value) { this->default_value = value; this->reset(); } - /* -------------------------------------------------------------------------- */ -template -void InternalField::reset() { - for(UInt g = _not_ghost; g <= _ghost; ++g) { - GhostType gt = (GhostType) g; - - typename ElementTypeMapArray::type_iterator it = this->firstType(spatial_dimension, gt, element_kind); - typename ElementTypeMapArray::type_iterator end = this->lastType(spatial_dimension, gt, element_kind); - for(; it != end; ++it) { - Array & vect = this->operator()(*it, gt); +template void InternalField::reset() { + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { + + type_iterator it = this->firstType(*gt); + type_iterator end = this->lastType(*gt); + for (; it != end; ++it) { + Array & vect = this->operator()(*it, *gt); vect.clear(); this->setArrayValues(vect.storage(), - vect.storage() + vect.getSize() * vect.getNbComponent()); + vect.storage() + + vect.getSize() * vect.getNbComponent()); } } } /* -------------------------------------------------------------------------- */ -template +template void InternalField::internalInitialize(UInt nb_component) { - if(!this->is_init) { + if (!this->is_init) { this->nb_component = nb_component; - for(UInt g = _not_ghost; g <= _ghost; ++g) { - GhostType gt = (GhostType) g; - typename ElementTypeMapArray::type_iterator it - = element_filter.firstType(spatial_dimension, gt, element_kind); - typename ElementTypeMapArray::type_iterator end - = element_filter.lastType(spatial_dimension, gt, element_kind); - - for(; it != end; ++it) { - UInt nb_element = element_filter(*it, gt).getSize(); - UInt nb_quadrature_points = fem->getNbIntegrationPoints(*it, gt); - if(this->exists(*it, gt)) - this->operator()(*it, gt).resize(nb_element * nb_quadrature_points); - else - this->alloc(nb_element * nb_quadrature_points, nb_component, *it, gt); + + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { + filter_type_iterator it = this->filterFirstType(*gt); + filter_type_iterator end = this->filterLastType(*gt); + + for (; it != end; ++it) { + UInt nb_element = this->element_filter(*it, *gt).getSize(); + UInt nb_quadrature_points = this->fem->getNbIntegrationPoints(*it, *gt); + if (this->exists(*it, *gt)) + this->operator()(*it, *gt).resize(nb_element * nb_quadrature_points); + else + this->alloc(nb_element * nb_quadrature_points, nb_component, *it, + *gt); } } this->material.registerInternal(*this); this->is_init = true; } this->reset(); - if(previous_values) previous_values->internalInitialize(nb_component); + if (this->previous_values) + this->previous_values->internalInitialize(nb_component); } /* -------------------------------------------------------------------------- */ -template +template void InternalField::setArrayValues(T * begin, T * end) { - for(; begin < end; ++begin) *begin = default_value; + for (; begin < end; ++begin) + *begin = this->default_value; } /* -------------------------------------------------------------------------- */ -template -void InternalField::saveCurrentValues() { - AKANTU_DEBUG_ASSERT(previous_values != NULL, - "The history of the internal " << this->getID() - << " has not been activated"); - - if(!is_init) return; - - for(UInt g = _not_ghost; g <= _ghost; ++g) { - GhostType gt = (GhostType) g; - typename ElementTypeMapArray::type_iterator it = this->firstType(spatial_dimension, gt, element_kind); - typename ElementTypeMapArray::type_iterator end = this->lastType(spatial_dimension, gt, element_kind); - for(; it != end; ++it) { - this->previous_values->operator()(*it, gt).copy(this->operator()(*it, gt)); +template void InternalField::saveCurrentValues() { + AKANTU_DEBUG_ASSERT(this->previous_values != NULL, + "The history of the internal " + << this->getID() << " has not been activated"); + + if (!this->is_init) + return; + + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { + type_iterator it = this->firstType(*gt); + type_iterator end = this->lastType(*gt); + for (; it != end; ++it) { + this->previous_values->operator()(*it, *gt) + .copy(this->operator()(*it, *gt)); } } } /* -------------------------------------------------------------------------- */ -template -void InternalField::removeIntegrationPoints(const ElementTypeMapArray & new_numbering) { - for(UInt g = _not_ghost; g <= _ghost; ++g) { - GhostType gt = (GhostType) g; - ElementTypeMapArray::type_iterator it = new_numbering.firstType(_all_dimensions, gt, _ek_not_defined); - ElementTypeMapArray::type_iterator end = new_numbering.lastType(_all_dimensions, gt, _ek_not_defined); +template +void InternalField::removeIntegrationPoints( + const ElementTypeMapArray & new_numbering) { + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { + ElementTypeMapArray::type_iterator it = + new_numbering.firstType(_all_dimensions, *gt, _ek_not_defined); + ElementTypeMapArray::type_iterator end = + new_numbering.lastType(_all_dimensions, *gt, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; - if(this->exists(type, gt)){ - Array & vect = this->operator()(type, gt); - if (!vect.getSize()) - continue; - const Array & renumbering = new_numbering(type, gt); - - UInt nb_quad_per_elem = fem->getNbIntegrationPoints(type, gt); - UInt nb_component = vect.getNbComponent(); - - Array tmp(renumbering.getSize()*nb_quad_per_elem, nb_component); - - AKANTU_DEBUG_ASSERT(tmp.getSize() == vect.getSize(), "Something strange append some mater was created from nowhere!!"); - - AKANTU_DEBUG_ASSERT(tmp.getSize() == vect.getSize(), "Something strange append some mater was created or disappeared in "<< vect.getID() << "("<< vect.getSize() <<"!=" << tmp.getSize() <<") ""!!"); - - UInt new_size = 0; - for (UInt i = 0; i < renumbering.getSize(); ++i) { - UInt new_i = renumbering(i); - if(new_i != UInt(-1)) { - memcpy(tmp.storage() + new_i * nb_component * nb_quad_per_elem, - vect.storage() + i * nb_component * nb_quad_per_elem, - nb_component * nb_quad_per_elem * sizeof(T)); - ++new_size; - } - } - tmp.resize(new_size * nb_quad_per_elem); - vect.copy(tmp); + if (this->exists(type, *gt)) { + Array & vect = this->operator()(type, *gt); + if (!vect.getSize()) + continue; + const Array & renumbering = new_numbering(type, *gt); + + UInt nb_quad_per_elem = fem->getNbIntegrationPoints(type, *gt); + UInt nb_component = vect.getNbComponent(); + + Array tmp(renumbering.getSize() * nb_quad_per_elem, nb_component); + + AKANTU_DEBUG_ASSERT( + tmp.getSize() == vect.getSize(), + "Something strange append some mater was created from nowhere!!"); + + AKANTU_DEBUG_ASSERT( + tmp.getSize() == vect.getSize(), + "Something strange append some mater was created or disappeared in " + << vect.getID() << "(" << vect.getSize() + << "!=" << tmp.getSize() << ") " + "!!"); + + UInt new_size = 0; + for (UInt i = 0; i < renumbering.getSize(); ++i) { + UInt new_i = renumbering(i); + if (new_i != UInt(-1)) { + memcpy(tmp.storage() + new_i * nb_component * nb_quad_per_elem, + vect.storage() + i * nb_component * nb_quad_per_elem, + nb_component * nb_quad_per_elem * sizeof(T)); + ++new_size; + } + } + tmp.resize(new_size * nb_quad_per_elem); + vect.copy(tmp); } } } } /* -------------------------------------------------------------------------- */ -template +template void InternalField::printself(std::ostream & stream, UInt indent) const { stream << "InternalField [ " << this->getID(); #if !defined(AKANTU_NDEBUG) - if(AKANTU_DEBUG_TEST(dblDump)) { + if (AKANTU_DEBUG_TEST(dblDump)) { stream << std::endl; ElementTypeMapArray::printself(stream, indent + 3); } else { #endif - stream << " {" - << this->getData(_not_ghost).size() << " types - " - << this->getData(_ghost).size() << " ghost types" - << "}"; + stream << " {" << this->getData(_not_ghost).size() << " types - " + << this->getData(_ghost).size() << " ghost types" + << "}"; #if !defined(AKANTU_NDEBUG) } #endif stream << " ]"; } /* -------------------------------------------------------------------------- */ -template<> -inline void ParsableParamTyped< InternalField >::parseParam(const ParserParameter & in_param) { +template <> +inline void ParsableParamTyped >::parseParam( + const ParserParameter & in_param) { ParsableParam::parseParam(in_param); Real r = in_param; param.setDefaultValue(r); } /* -------------------------------------------------------------------------- */ -template -inline InternalField::operator T() const { +template inline InternalField::operator T() const { return default_value; } - __END_AKANTU__ #endif /* __AKANTU_INTERNAL_FIELD_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc index 98ff52320..908db8240 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc +++ b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc @@ -1,640 +1,618 @@ /** * @file material_cohesive.cc * * @author Seyedeh Mohadeseh Taheri Mousavi * @author Marco Vocialta * @author Nicolas Richart * * @date creation: Wed Feb 22 2012 * @date last modification: Tue Jul 29 2014 * * @brief Specialization of the material class for cohesive elements * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" #include "aka_random_generator.hh" #include "shape_cohesive.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ MaterialCohesive::MaterialCohesive(SolidMechanicsModel & model, const ID & id) : Material(model, id), facet_filter("facet_filter", id, this->getMemoryID()), fem_cohesive(&(model.getFEEngineClass("CohesiveFEEngine"))), reversible_energy("reversible_energy", *this), total_energy("total_energy", *this), opening("opening", *this), opening_old("opening (old)", *this), tractions("tractions", *this), tractions_old("tractions (old)", *this), contact_tractions("contact_tractions", *this), contact_opening("contact_opening", *this), delta_max("delta max", *this), use_previous_delta_max(false), damage("damage", *this), sigma_c("sigma_c", *this), normal(0, spatial_dimension, "normal") { AKANTU_DEBUG_IN(); this->model = dynamic_cast(&model); this->registerParam("sigma_c", sigma_c, _pat_parsable | _pat_readable, "Critical stress"); this->registerParam("delta_c", delta_c, Real(0.), _pat_parsable | _pat_readable, "Critical displacement"); this->model->getMesh().initElementTypeMapArray(this->element_filter, 1, spatial_dimension, false, _ek_cohesive); if (this->model->getIsExtrinsic()) this->model->getMeshFacets().initElementTypeMapArray(facet_filter, 1, spatial_dimension - 1); - this->fem = &(model.getFEEngineClass("CohesiveFEEngine")); - - this->gradu.setElementKind(_ek_cohesive); - this->stress.setElementKind(_ek_cohesive); - this->eigengradu.setElementKind(_ek_cohesive); + this->reversible_energy.initialize(1 ); + this->total_energy .initialize(1 ); + this->tractions_old .initialize(spatial_dimension); + this->tractions .initialize(spatial_dimension); + this->opening_old .initialize(spatial_dimension); + this->contact_tractions.initialize(spatial_dimension); + this->contact_opening .initialize(spatial_dimension); + this->opening .initialize(spatial_dimension); + this->delta_max .initialize(1 ); + this->damage .initialize(1 ); - this->gradu.setFEEngine(*fem); - this->stress.setFEEngine(*fem); - this->eigengradu.setFEEngine(*fem); + if (this->model->getIsExtrinsic()) this->sigma_c.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MaterialCohesive::~MaterialCohesive() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); - - this->reversible_energy.initialize(1 ); - this->total_energy .initialize(1 ); - this->tractions_old .initialize(spatial_dimension); - this->tractions .initialize(spatial_dimension); - this->opening_old .initialize(spatial_dimension); - this->contact_tractions.initialize(spatial_dimension); - this->contact_opening .initialize(spatial_dimension); - this->opening .initialize(spatial_dimension); - this->delta_max .initialize(1 ); - this->damage .initialize(1 ); - - if (model->getIsExtrinsic()) this->sigma_c.initialize(1); - if (use_previous_delta_max) delta_max.initializeHistory(); - + if (this->use_previous_delta_max) this->delta_max.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Tractions", tractions); #endif Array & residual = const_cast &>(model->getResidual()); 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); for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; const Array & shapes = fem_cohesive->getShapes(*it, ghost_type); Array & traction = tractions(*it, ghost_type); Array & contact_traction = contact_tractions(*it, ghost_type); UInt size_of_shapes = shapes.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = fem_cohesive->getNbIntegrationPoints(*it, ghost_type); /// compute @f$t_i N_a@f$ Array * traction_cpy = new Array(nb_element * nb_quadrature_points, spatial_dimension * size_of_shapes); Array::iterator > traction_it = traction.begin(spatial_dimension, 1); Array::iterator > contact_traction_it = contact_traction.begin(spatial_dimension, 1); Array::const_iterator > shapes_filtered_begin = shapes.begin(1, size_of_shapes); Array::iterator > traction_cpy_it = traction_cpy->begin(spatial_dimension, size_of_shapes); Matrix traction_tmp(spatial_dimension, 1); for (UInt el = 0; el < nb_element; ++el) { UInt current_quad = elem_filter(el) * nb_quadrature_points; for (UInt q = 0; q < nb_quadrature_points; ++q, ++traction_it, ++contact_traction_it, ++current_quad, ++traction_cpy_it) { const Matrix & shapes_filtered = shapes_filtered_begin[current_quad]; traction_tmp.copy(*traction_it); traction_tmp += *contact_traction_it; traction_cpy_it->mul(traction_tmp, shapes_filtered); } } /** * compute @f$\int t \cdot N\, dS@f$ by @f$ \sum_q \mathbf{N}^t * \mathbf{t}_q \overline w_q J_q@f$ */ Array * int_t_N = new Array(nb_element, spatial_dimension*size_of_shapes, "int_t_N"); fem_cohesive->integrate(*traction_cpy, *int_t_N, spatial_dimension * size_of_shapes, *it, ghost_type, elem_filter); delete traction_cpy; int_t_N->extendComponentsInterlaced(2, int_t_N->getNbComponent()); Real * int_t_N_val = int_t_N->storage(); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < size_of_shapes * spatial_dimension; ++n) int_t_N_val[n] *= -1.; int_t_N_val += nb_nodes_per_element * spatial_dimension; } /// assemble model->getFEEngineBoundary().assembleArray(*int_t_N, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, elem_filter, 1); delete int_t_N; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast(model->getStiffnessMatrix()); 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); for(; it != last_type; ++it) { UInt nb_quadrature_points = fem_cohesive->getNbIntegrationPoints(*it, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); const Array & shapes = fem_cohesive->getShapes(*it, ghost_type); Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if(!nb_element) continue; UInt size_of_shapes = shapes.getNbComponent(); Array * shapes_filtered = new Array(nb_element*nb_quadrature_points, size_of_shapes, "filtered shapes"); Real * shapes_val = shapes.storage(); Real * shapes_filtered_val = shapes_filtered->storage(); UInt * elem_filter_val = elem_filter.storage(); for (UInt el = 0; el < nb_element; ++el) { shapes_val = shapes.storage() + elem_filter_val[el] * size_of_shapes * nb_quadrature_points; memcpy(shapes_filtered_val, shapes_val, size_of_shapes * nb_quadrature_points * sizeof(Real)); shapes_filtered_val += size_of_shapes * nb_quadrature_points; } /** * compute A matrix @f$ \mathbf{A} = \left[\begin{array}{c c c c c c c c c c c c} * 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 \\ * 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 \\ * 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 \\ * 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 \\ * 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 \\ * 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 * \end{array} \right]@f$ **/ // UInt size_of_A = spatial_dimension*size_of_shapes*spatial_dimension*nb_nodes_per_element; // Real * A = new Real[size_of_A]; // memset(A, 0, size_of_A*sizeof(Real)); Matrix A(spatial_dimension*size_of_shapes, spatial_dimension*nb_nodes_per_element); for ( UInt i = 0; i < spatial_dimension*size_of_shapes; ++i) { A(i, i) = 1; A(i, i + spatial_dimension*size_of_shapes) = -1; } /// compute traction computeTraction(ghost_type); /// get the tangent matrix @f$\frac{\partial{(t/\delta)}}{\partial{\delta}} @f$ Array * tangent_stiffness_matrix = new Array(nb_element * nb_quadrature_points, spatial_dimension * spatial_dimension, "tangent_stiffness_matrix"); // Array * normal = new Array(nb_element * nb_quadrature_points, spatial_dimension, "normal"); normal.resize(nb_quadrature_points); computeNormal(model->getCurrentPosition(), normal, *it, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ //computeOpening(model->getDisplacement(), opening(*it, ghost_type), *it, ghost_type); tangent_stiffness_matrix->clear(); computeTangentTraction(*it, *tangent_stiffness_matrix, normal, ghost_type); // delete normal; UInt size_at_nt_d_n_a = spatial_dimension*nb_nodes_per_element*spatial_dimension*nb_nodes_per_element; Array * at_nt_d_n_a = new Array (nb_element*nb_quadrature_points, size_at_nt_d_n_a, "A^t*N^t*D*N*A"); Array::iterator > shapes_filt_it = shapes_filtered->begin(size_of_shapes); Array::matrix_iterator D_it = tangent_stiffness_matrix->begin(spatial_dimension, spatial_dimension); Array::matrix_iterator At_Nt_D_N_A_it = at_nt_d_n_a->begin(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Array::matrix_iterator At_Nt_D_N_A_end = at_nt_d_n_a->end(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Matrix N (spatial_dimension, spatial_dimension * size_of_shapes); Matrix N_A (spatial_dimension, spatial_dimension * nb_nodes_per_element); Matrix D_N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); for(; At_Nt_D_N_A_it != At_Nt_D_N_A_end; ++At_Nt_D_N_A_it, ++D_it, ++shapes_filt_it) { N.clear(); /** * store the shapes in voigt notations matrix @f$\mathbf{N} = * \begin{array}{cccccc} N_0(\xi) & 0 & N_1(\xi) &0 & N_2(\xi) & 0 \\ * 0 & * N_0(\xi)& 0 &N_1(\xi)& 0 & N_2(\xi) \end{array} @f$ **/ for (UInt i = 0; i < spatial_dimension ; ++i) for (UInt n = 0; n < size_of_shapes; ++n) N(i, i + spatial_dimension * n) = (*shapes_filt_it)(n); /** * compute stiffness matrix @f$ \mathbf{K} = \delta \mathbf{U}^T * \int_{\Gamma_c} {\mathbf{P}^t \frac{\partial{\mathbf{t}}} {\partial{\delta}} * \mathbf{P} d\Gamma \Delta \mathbf{U}} @f$ **/ N_A.mul(N, A); D_N_A.mul(*D_it, N_A); (*At_Nt_D_N_A_it).mul(D_N_A, N_A); } delete tangent_stiffness_matrix; delete shapes_filtered; Array * K_e = new Array(nb_element, size_at_nt_d_n_a, "K_e"); fem_cohesive->integrate(*at_nt_d_n_a, *K_e, size_at_nt_d_n_a, *it, ghost_type, elem_filter); delete at_nt_d_n_a; model->getFEEngine().assembleMatrix(*K_e, K, spatial_dimension, *it, ghost_type, elem_filter); delete K_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- * * Compute traction from displacements * * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void MaterialCohesive::computeTraction(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Openings", opening); #endif 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); for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; UInt nb_quadrature_points = nb_element*fem_cohesive->getNbIntegrationPoints(*it, ghost_type); normal.resize(nb_quadrature_points); /// compute normals @f$\mathbf{n}@f$ computeNormal(model->getCurrentPosition(), normal, *it, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ computeOpening(model->getDisplacement(), opening(*it, ghost_type), *it, ghost_type); /// compute traction @f$\mathbf{t}@f$ computeTraction(normal, *it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeNormal(const Array & position, Array & normal, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (type == _cohesive_1d_2) fem_cohesive->computeNormalsOnIntegrationPoints(position, normal, type, ghost_type); else { #define COMPUTE_NORMAL(type) \ fem_cohesive->getShapeFunctions(). \ computeNormalsOnIntegrationPoints(position, \ normal, \ ghost_type, \ element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_NORMAL); #undef COMPUTE_NORMAL } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeOpening(const Array & displacement, Array & opening, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); #define COMPUTE_OPENING(type) \ fem_cohesive->getShapeFunctions(). \ interpolateOnIntegrationPoints(displacement, \ opening, \ spatial_dimension, \ ghost_type, \ element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_OPENING); #undef COMPUTE_OPENING AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeEnergies() { AKANTU_DEBUG_IN(); Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); Real * memory_space = new Real[2*spatial_dimension]; Vector b(memory_space, spatial_dimension); Vector h(memory_space + spatial_dimension, spatial_dimension); for(; it != last_type; ++it) { Array::iterator erev = reversible_energy(*it, _not_ghost).begin(); Array::iterator etot = total_energy(*it, _not_ghost).begin(); Array::vector_iterator traction_it = tractions(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator traction_old_it = tractions_old(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator opening_it = opening(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator opening_old_it = opening_old(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator traction_end = tractions(*it, _not_ghost).end(spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++traction_old_it, ++opening_it, ++opening_old_it, ++erev, ++etot) { /// trapezoidal integration b = *opening_it; b -= *opening_old_it; h = *traction_old_it; h += *traction_it; *etot += .5 * b.dot(h); *erev = .5 * traction_it->dot(*opening_it); } } delete [] memory_space; /// update old values it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); GhostType ghost_type = _not_ghost; for(; it != last_type; ++it) { tractions_old(*it, ghost_type).copy(tractions(*it, ghost_type)); opening_old(*it, ghost_type).copy(opening(*it, ghost_type)); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getReversibleEnergy() { AKANTU_DEBUG_IN(); Real erev = 0.; /// integrate reversible energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { erev += fem_cohesive->integrate(reversible_energy(*it, _not_ghost), *it, _not_ghost, element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return erev; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getDissipatedEnergy() { AKANTU_DEBUG_IN(); Real edis = 0.; /// integrate dissipated energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { Array dissipated_energy(total_energy(*it, _not_ghost)); dissipated_energy -= reversible_energy(*it, _not_ghost); edis += fem_cohesive->integrate(dissipated_energy, *it, _not_ghost, element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return edis; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getContactEnergy() { AKANTU_DEBUG_IN(); Real econ = 0.; /// integrate contact energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { Array & el_filter = element_filter(*it, _not_ghost); UInt nb_quad_per_el = fem_cohesive->getNbIntegrationPoints(*it, _not_ghost); UInt nb_quad_points = el_filter.getSize() * nb_quad_per_el; Array contact_energy(nb_quad_points); Array::vector_iterator contact_traction_it = contact_tractions(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator contact_opening_it = contact_opening(*it, _not_ghost).begin(spatial_dimension); /// loop on each quadrature point for (UInt el = 0; el < nb_quad_points; ++contact_traction_it, ++contact_opening_it, ++el) { contact_energy(el) = .5 * contact_traction_it->dot(*contact_opening_it); } econ += fem_cohesive->integrate(contact_energy, *it, _not_ghost, el_filter); } AKANTU_DEBUG_OUT(); return econ; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getEnergy(std::string type) { AKANTU_DEBUG_IN(); if (type == "reversible") return getReversibleEnergy(); else if (type == "dissipated") return getDissipatedEnergy(); else if (type == "cohesive contact") return getContactEnergy(); AKANTU_DEBUG_OUT(); return 0.; } -/* -------------------------------------------------------------------------- */ -inline ElementTypeMap MaterialCohesive::getInternalDataPerElem(const ID & id, - const ElementKind & element_kind, - const ID & fe_engine_id) const { - if (element_kind == _ek_cohesive) { - return Material::getInternalDataPerElem(id, element_kind, "CohesiveFEEngine"); - } else { - return Material::getInternalDataPerElem(id, element_kind, fe_engine_id); - } -} - /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh index 139db880c..8c1909a21 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh +++ b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh @@ -1,263 +1,258 @@ /** * @file material_cohesive.hh * * @author Seyedeh Mohadeseh Taheri Mousavi * @author Marco Vocialta * @author Nicolas Richart * * @date creation: Wed Feb 22 2012 * @date last modification: Tue Jul 29 2014 * * @brief Specialization of the material class for cohesive elements * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "fe_engine_template.hh" #include "aka_common.hh" #include "cohesive_internal_field.hh" #include "cohesive_element_inserter.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_HH__ #define __AKANTU_MATERIAL_COHESIVE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class SolidMechanicsModelCohesive; } __BEGIN_AKANTU__ class MaterialCohesive : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef FEEngineTemplate MyFEEngineCohesiveType; + ShapeLagrange, _ek_cohesive> MyFEEngineCohesiveType; public: MaterialCohesive(SolidMechanicsModel& model, const ID & id = ""); virtual ~MaterialCohesive(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter virtual void initMaterial(); /// compute tractions (including normals and openings) void computeTraction(GhostType ghost_type = _not_ghost); /// assemble residual void assembleResidual(GhostType ghost_type = _not_ghost); /// compute reversible and total energies by element void computeEnergies(); /// check stress for cohesive elements' insertion, by default it /// also updates the cohesive elements' data virtual void checkInsertion(bool check_only = false) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// check delta_max for cohesive elements in case of no convergence /// in the solveStep (only for extrinsic-implicit) virtual void checkDeltaMax(GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// interpolate stress on given positions for each element (empty /// implemantation to avoid the generic call to be done on cohesive elements) virtual void interpolateStress(__attribute__((unused)) const ElementType type, - __attribute__((unused)) Array & result) { }; + __attribute__((unused)) Array & result) { }; /// compute the stresses virtual void computeAllStresses(__attribute__((unused)) GhostType ghost_type = _not_ghost) { }; // add the facet to be handled by the material UInt addFacet(const Element & element); protected: virtual void computeTangentTraction(__attribute__((unused)) const ElementType & el_type, - __attribute__((unused)) Array & tangent_matrix, - __attribute__((unused)) const Array & normal, - __attribute__((unused)) GhostType ghost_type = _not_ghost) { + __attribute__((unused)) Array & tangent_matrix, + __attribute__((unused)) const Array & normal, + __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } - /// get the internal data for an element - virtual ElementTypeMap getInternalDataPerElem(const ID & id, - const ElementKind & element_kind, - const ID & fe_engine_id) const; - /// compute the normal void computeNormal(const Array & position, - Array & normal, - ElementType type, - GhostType ghost_type); + Array & normal, + ElementType type, + GhostType ghost_type); /// compute the opening void computeOpening(const Array & displacement, - Array & normal, - ElementType type, - GhostType ghost_type); + Array & normal, + ElementType type, + GhostType ghost_type); template void computeNormal(const Array & position, - Array & normal, - GhostType ghost_type); + Array & normal, + GhostType ghost_type); /// assemble stiffness void assembleStiffnessMatrix(GhostType ghost_type); /// constitutive law virtual void computeTraction(const Array & normal, - ElementType el_type, - GhostType ghost_type = _not_ghost) = 0; + ElementType el_type, + GhostType ghost_type = _not_ghost) = 0; /// parallelism functions inline UInt getNbDataForElements(const Array & elements, - SynchronizationTag tag) const; + SynchronizationTag tag) const; inline void packElementData(CommunicationBuffer & buffer, - const Array & elements, - SynchronizationTag tag) const; + const Array & elements, + SynchronizationTag tag) const; inline void unpackElementData(CommunicationBuffer & buffer, - const Array & elements, - SynchronizationTag tag); + const Array & elements, + SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the opening AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Opening, opening, Real); /// get the traction AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Traction, tractions, Real); /// get damage AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real); /// get facet filter AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO(FacetFilter, facet_filter, const ElementTypeMapArray &); // AKANTU_GET_MACRO(ElementFilter, element_filter, const ElementTypeMapArray &); /// compute reversible energy Real getReversibleEnergy(); /// compute dissipated energy Real getDissipatedEnergy(); /// compute contact energy Real getContactEnergy(); /// get energy virtual Real getEnergy(std::string type); /// return the energy (identified by id) for the provided element virtual Real getEnergy(std::string energy_id, ElementType type, UInt index) { return Material::getEnergy(energy_id, type, index); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of facets assigned to this material ElementTypeMapArray facet_filter; /// Link to the cohesive fem object in the model MyFEEngineCohesiveType * fem_cohesive; private: /// reversible energy by quadrature point CohesiveInternalField reversible_energy; /// total energy by quadrature point CohesiveInternalField total_energy; protected: /// opening in all elements and quadrature points CohesiveInternalField opening; /// opening in all elements and quadrature points (previous time step) CohesiveInternalField opening_old; /// traction in all elements and quadrature points CohesiveInternalField tractions; /// traction in all elements and quadrature points (previous time step) CohesiveInternalField tractions_old; /// traction due to contact CohesiveInternalField contact_tractions; /// normal openings for contact tractions CohesiveInternalField contact_opening; /// maximum displacement CohesiveInternalField delta_max; /// tell if the previous delta_max state is needed (in iterative schemes) bool use_previous_delta_max; /// damage CohesiveInternalField damage; /// pointer to the solid mechanics model for cohesive elements SolidMechanicsModelCohesive * model; /// critical stress RandomInternalField sigma_c; /// critical displacement Real delta_c; /// array to temporarily store the normals Array normal; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_inline_impl.cc" __END_AKANTU__ #include "cohesive_internal_field_tmpl.hh" #endif /* __AKANTU_MATERIAL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc index 6466fbd5e..e7f819708 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc @@ -1,743 +1,743 @@ /** * @file material_reinforcement.cc * * @author Lucas Frérot * * @date creation: Thu Mar 12 2015 * @date last modification: Thu Mar 12 2015 * * @brief Reinforcement material * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_voigthelper.hh" #include "material_reinforcement.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template MaterialReinforcement::MaterialReinforcement(SolidMechanicsModel & model, UInt spatial_dimension, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Material(model, dim, mesh, fe_engine, id), // /!\ dim, not spatial_dimension ! model(NULL), stress_embedded("stress_embedded", *this, 1, fe_engine, this->element_filter), gradu_embedded("gradu_embedded", *this, 1, fe_engine, this->element_filter), directing_cosines("directing_cosines", *this, 1, fe_engine, this->element_filter), pre_stress("pre_stress", *this, 1, fe_engine, this->element_filter), area(1.0), shape_derivatives() { AKANTU_DEBUG_IN(); this->initialize(model); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::initialize(SolidMechanicsModel & a_model) { this->model = dynamic_cast(&a_model); AKANTU_DEBUG_ASSERT(this->model != NULL, "MaterialReinforcement needs an EmbeddedInterfaceModel"); 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"); // Fool the AvgHomogenizingFunctor //stress.initialize(dim * dim); // Reallocate the element filter this->element_filter.free(); this->model->getInterfaceMesh().initElementTypeMapArray(this->element_filter, 1, 1, false, _ek_regular); } /* -------------------------------------------------------------------------- */ template MaterialReinforcement::~MaterialReinforcement() { AKANTU_DEBUG_IN(); ElementTypeMap *>::type_iterator it = shape_derivatives.firstType(); ElementTypeMap *>::type_iterator end = shape_derivatives.lastType(); for (; it != end ; ++it) { delete shape_derivatives(*it, _not_ghost); delete shape_derivatives(*it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::initMaterial() { Material::initMaterial(); stress_embedded.initialize(dim * dim); gradu_embedded.initialize(dim * dim); pre_stress.initialize(1); /// We initialise the stuff that is not going to change during the simulation this->allocBackgroundShapeDerivatives(); this->initBackgroundShapeDerivatives(); this->initDirectingCosines(); } /* -------------------------------------------------------------------------- */ /** * 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 *>. The outer ElementTypeMap * refers to the embedded types, and the inner refers to the background types. */ template void MaterialReinforcement::allocBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); Mesh & mesh = model->getMesh(); ghost_type_t::iterator int_ghost_it = ghost_type_t::begin(); // Loop over interface ghosts for (; int_ghost_it != ghost_type_t::end() ; ++int_ghost_it) { Mesh::type_iterator interface_type_it = interface_mesh.firstType(1, *int_ghost_it); Mesh::type_iterator interface_type_end = interface_mesh.lastType(1, *int_ghost_it); // Loop over interface types for (; interface_type_it != interface_type_end ; ++interface_type_it) { Mesh::type_iterator background_type_it = mesh.firstType(dim, *int_ghost_it); Mesh::type_iterator background_type_end = mesh.lastType(dim, *int_ghost_it); // Loop over background types for (; background_type_it != background_type_end ; ++background_type_it) { const ElementType & int_type = *interface_type_it; const ElementType & back_type = *background_type_it; const GhostType & int_ghost = *int_ghost_it; std::string shaped_id = "embedded_shape_derivatives"; if (int_ghost == _ghost) shaped_id += ":ghost"; ElementTypeMapArray * shaped_etma = new ElementTypeMapArray(shaped_id, this->name); UInt nb_points = Mesh::getNbNodesPerElement(back_type); UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbIntegrationPoints(int_type); UInt nb_elements = element_filter(int_type, int_ghost).getSize(); // Alloc the background ElementTypeMapArray shaped_etma->alloc(nb_elements * nb_quad_points, dim * nb_points, back_type); // Insert the background ElementTypeMapArray in the interface ElementTypeMap shape_derivatives(shaped_etma, int_type, int_ghost); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::initBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); Mesh & mesh = model->getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, _not_ghost); Mesh::type_iterator type_end = mesh.lastType(dim, _not_ghost); for (; type_it != type_end ; ++type_it) { computeBackgroundShapeDerivatives(*type_it, _not_ghost); //computeBackgroundShapeDerivatives(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::initDirectingCosines() { AKANTU_DEBUG_IN(); Mesh & mesh = model->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 = getTangentStiffnessVoigtSize(dim); directing_cosines.initialize(voigt_size * voigt_size); for (; type_it != type_end ; ++type_it) { computeDirectingCosines(*type_it, _not_ghost); //computeDirectingCosines(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->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 void MaterialReinforcement::updateResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); computeAllStresses(ghost_type); assembleResidual(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->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) { assembleResidual(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::computeGradU(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbIntegrationPoints(type); Array & gradu_vec = gradu_embedded(type, ghost_type); Mesh::type_iterator back_it = model->getMesh().firstType(dim, ghost_type); Mesh::type_iterator back_end = model->getMesh().lastType(dim, ghost_type); for (; back_it != back_end ; ++back_it) { UInt nodes_per_background_e = Mesh::getNbNodesPerElement(*back_it); Array & shapesd = shape_derivatives(type, ghost_type)->operator()(*back_it, ghost_type); Array * background_filter = new Array(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, *back_it, type, ghost_type); Array * disp_per_element = new Array(0, dim * nodes_per_background_e, "disp_elem"); FEEngine::extractNodalToElementField(model->getMesh(), model->getDisplacement(), *disp_per_element, *back_it, ghost_type, *background_filter); Array::matrix_iterator disp_it = disp_per_element->begin(dim, nodes_per_background_e); Array::matrix_iterator disp_end = disp_per_element->end(dim, nodes_per_background_e); Array::matrix_iterator shapes_it = shapesd.begin(dim, nodes_per_background_e); Array::matrix_iterator grad_u_it = gradu_vec.begin(dim, dim); for (; disp_it != disp_end ; ++disp_it) { for (UInt i = 0; i < nb_quad_points; i++, ++shapes_it, ++grad_u_it) { Matrix & B = *shapes_it; Matrix & du = *grad_u_it; Matrix & u = *disp_it; du.mul(u, B); } } delete background_filter; delete disp_per_element; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = model->getInterfaceMesh().firstType(); Mesh::type_iterator last_type = model->getInterfaceMesh().lastType(); for(; it != last_type; ++it) { computeGradU(*it, ghost_type); computeStress(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::assembleResidual(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = model->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) { assembleResidualInterface(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 void MaterialReinforcement::assembleResidualInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt voigt_size = getTangentStiffnessVoigtSize(dim); Array & residual = const_cast &>(model->getResidual()); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); FEEngine & background_engine = model->getFEEngine(); Array & elem_filter = 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.getSize(); UInt back_dof = dim * nodes_per_background_e; Array & shapesd = shape_derivatives(interface_type, ghost_type)->operator()(background_type, ghost_type); Array * integrant = new Array(nb_quadrature_points * nb_element, back_dof, "integrant"); Array::vector_iterator integrant_it = integrant->begin(back_dof); Array::vector_iterator integrant_end = integrant->end(back_dof); Array::matrix_iterator B_it = shapesd.begin(dim, nodes_per_background_e); Array::matrix_iterator C_it = directing_cosines(interface_type, ghost_type).begin(voigt_size, voigt_size); Array::matrix_iterator sigma_it = stress_embedded(interface_type, ghost_type).begin(dim, dim); Vector sigma(voigt_size); Matrix Bvoigt(voigt_size, back_dof); Vector Ct_sigma(voigt_size); for (; integrant_it != integrant_end ; ++integrant_it, ++B_it, ++C_it, ++sigma_it) { VoigtHelper::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, nodes_per_background_e); Matrix & C = *C_it; Vector & BtCt_sigma = *integrant_it; stressTensorToVoigtVector(*sigma_it, sigma); Ct_sigma.mul(C, sigma); BtCt_sigma.mul(Bvoigt, Ct_sigma); BtCt_sigma *= area; } Array * residual_interface = new Array(nb_element, back_dof, "residual_interface"); interface_engine.integrate(*integrant, *residual_interface, back_dof, interface_type, ghost_type, elem_filter); delete integrant; Array * background_filter = new Array(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, background_type, interface_type, ghost_type); background_engine.assembleArray(*residual_interface, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), dim, background_type, ghost_type, *background_filter, -1.0); delete residual_interface; delete background_filter; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::filterInterfaceBackgroundElements(Array & filter, const ElementType & type, const ElementType & interface_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); filter.resize(0); filter.clear(); Array & elements = model->getInterfaceAssociatedElements(interface_type, ghost_type); Array & elem_filter = element_filter(interface_type, ghost_type); Array::scalar_iterator filter_it = elem_filter.begin(), filter_end = elem_filter.end(); for (; filter_it != filter_end ; ++filter_it) { Element & elem = elements(*filter_it); if (elem.type == type) filter.push_back(elem.element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::computeDirectingCosines(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = this->model->getInterfaceMesh(); const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const UInt steel_dof = dim * nb_nodes_per_element; const UInt voigt_size = getTangentStiffnessVoigtSize(dim); const UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbIntegrationPoints(type, ghost_type); Array node_coordinates(this->element_filter(type, ghost_type).getSize(), steel_dof); this->model->getFEEngine().template extractNodalToElementField(interface_mesh, interface_mesh.getNodes(), node_coordinates, type, ghost_type, this->element_filter(type, ghost_type)); Array::matrix_iterator directing_cosines_it = directing_cosines(type, ghost_type).begin(voigt_size, voigt_size); Array::matrix_iterator node_coordinates_it = node_coordinates.begin(dim, nb_nodes_per_element); Array::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 & nodes = *node_coordinates_it; Matrix & cosines = *directing_cosines_it; computeDirectingCosinesOnQuad(nodes, cosines); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialReinforcement::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = model->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 void MaterialReinforcement::assembleStiffnessMatrixInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt voigt_size = getTangentStiffnessVoigtSize(dim); SparseMatrix & K = const_cast(model->getStiffnessMatrix()); FEEngine & background_engine = model->getFEEngine(); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); Array & elem_filter = element_filter(interface_type, ghost_type); Array & grad_u = gradu_embedded(interface_type, ghost_type); UInt nb_element = elem_filter.getSize(); 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 * tangent_moduli = new Array(nb_element * nb_quadrature_points, 1, "interface_tangent_moduli"); tangent_moduli->clear(); computeTangentModuli(interface_type, *tangent_moduli, ghost_type); Array & shapesd = shape_derivatives(interface_type, ghost_type)->operator()(background_type, ghost_type); Array * integrant = new Array(nb_element * nb_quadrature_points, integrant_size * integrant_size, "B^t*C^t*D*C*B"); integrant->clear(); /// Temporary matrices for integrant product Matrix Bvoigt(voigt_size, back_dof); Matrix DC(voigt_size, voigt_size); Matrix DCB(voigt_size, back_dof); Matrix CtDCB(voigt_size, back_dof); Array::scalar_iterator D_it = tangent_moduli->begin(); Array::scalar_iterator D_end = tangent_moduli->end(); Array::matrix_iterator C_it = directing_cosines(interface_type, ghost_type).begin(voigt_size, voigt_size); Array::matrix_iterator B_it = shapesd.begin(dim, nodes_per_background_e); Array::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 & C = *C_it; Matrix & B = *B_it; Matrix & BtCtDCB = *integrant_it; VoigtHelper::transferBMatrixToSymVoigtBMatrix(B, Bvoigt, nodes_per_background_e); DC.clear(); DC(0, 0) = D * area; DC *= C; DCB.mul(DC, Bvoigt); CtDCB.mul(C, DCB); BtCtDCB.mul(Bvoigt, CtDCB); } delete tangent_moduli; Array * K_interface = new Array(nb_element, integrant_size * integrant_size, "K_interface"); interface_engine.integrate(*integrant, *K_interface, integrant_size * integrant_size, interface_type, ghost_type, elem_filter); delete integrant; Array * background_filter = new Array(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, background_type, interface_type, ghost_type); background_engine.assembleMatrix(*K_interface, K, dim, background_type, ghost_type, *background_filter); delete K_interface; delete background_filter; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// In this function, type and ghost_type refer to background elements template void MaterialReinforcement::computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); FEEngine & engine = model->getFEEngine(); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); Mesh::type_iterator interface_type = interface_mesh.firstType(); Mesh::type_iterator interface_last = interface_mesh.lastType(); for (; interface_type != interface_last ; ++interface_type) { Array & filter = element_filter(*interface_type, ghost_type); const UInt nb_elements = filter.getSize(); const UInt nb_nodes = Mesh::getNbNodesPerElement(type); const UInt nb_quad_per_element = interface_engine.getNbIntegrationPoints(*interface_type); Array quad_pos(nb_quad_per_element * nb_elements, dim, "interface_quad_points"); quad_pos.resize(nb_quad_per_element * nb_elements); interface_engine.interpolateOnIntegrationPoints(interface_mesh.getNodes(), quad_pos, dim, *interface_type, ghost_type, filter); Array & background_shapesd = shape_derivatives(*interface_type, ghost_type)->operator()(type, ghost_type); background_shapesd.clear(); Array * background_elements = new Array(nb_elements, 1, "computeBackgroundShapeDerivatives:background_filter"); filterInterfaceBackgroundElements(*background_elements, type, *interface_type, ghost_type); Array::scalar_iterator back_it = background_elements->begin(), back_end = background_elements->end(); Array::matrix_iterator shapesd_it = background_shapesd.begin(dim, nb_nodes); Array::vector_iterator quad_pos_it = quad_pos.begin(dim); for (; back_it != back_end ; ++back_it) { for (UInt i = 0 ; i < nb_quad_per_element ; i++, ++shapesd_it, ++quad_pos_it) engine.computeShapeDerivatives(*quad_pos_it, *back_it, type, *shapesd_it, ghost_type); } delete background_elements; } AKANTU_DEBUG_OUT(); } template Real MaterialReinforcement::getEnergy(std::string id) { AKANTU_DEBUG_IN(); if (id == "potential") { Real epot = 0.; computePotentialEnergyByElements(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension), end = element_filter.lastType(spatial_dimension); for (; it != end ; ++it) { FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); epot += interface_engine.integrate(potential_energy(*it, _not_ghost), *it, _not_ghost, element_filter(*it, _not_ghost)); epot *= area; } return epot; } AKANTU_DEBUG_OUT(); return 0; } -/* -------------------------------------------------------------------------- */ -template -ElementTypeMap MaterialReinforcement::getInternalDataPerElem(const ID & field_name, - const ElementKind & kind, - const ID & fe_engine_id) const { - return Material::getInternalDataPerElem(field_name, kind, "EmbeddedInterfaceFEEngine"); -} - - -/* -------------------------------------------------------------------------- */ -// Author is Guillaume Anciaux, see material.cc -template -void MaterialReinforcement::flattenInternal(const std::string & field_id, - ElementTypeMapArray & internal_flat, - const GhostType ghost_type, - ElementKind element_kind) const { - AKANTU_DEBUG_IN(); - - if (field_id == "stress_embedded" || field_id == "inelastic_strain") { - Material::flattenInternalIntern(field_id, - internal_flat, - 1, - ghost_type, - _ek_not_defined, - &(this->element_filter), - &(this->model->getInterfaceMesh())); - } - - AKANTU_DEBUG_OUT(); -} +// /* -------------------------------------------------------------------------- */ +// template +// ElementTypeMap MaterialReinforcement::getInternalDataPerElem(const ID & field_name, +// const ElementKind & kind, +// const ID & fe_engine_id) const { +// return Material::getInternalDataPerElem(field_name, kind, "EmbeddedInterfaceFEEngine"); +// } + + +// /* -------------------------------------------------------------------------- */ +// // Author is Guillaume Anciaux, see material.cc +// template +// void MaterialReinforcement::flattenInternal(const std::string & field_id, +// ElementTypeMapArray & internal_flat, +// const GhostType ghost_type, +// ElementKind element_kind) const { +// AKANTU_DEBUG_IN(); + +// if (field_id == "stress_embedded" || field_id == "inelastic_strain") { +// Material::flattenInternalIntern(field_id, +// internal_flat, +// 1, +// ghost_type, +// _ek_not_defined, +// &(this->element_filter), +// &(this->model->getInterfaceMesh())); +// } + +// AKANTU_DEBUG_OUT(); +// } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(MaterialReinforcement); /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh index e6b5ffeb6..1969cd56f 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh @@ -1,197 +1,197 @@ /** * @file material_reinforcement.hh * * @author Lucas Frérot * * @date creation: Thu Mar 12 2015 * @date last modification: Thu Mar 12 2015 * * @brief Reinforcement material * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_REINFORCEMENT_HH__ #define __AKANTU_MATERIAL_REINFORCEMENT_HH__ #include "aka_common.hh" #include "material.hh" #include "embedded_interface_model.hh" #include "embedded_internal_field.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /** * @brief Material used to represent embedded reinforcements * * This class is used for computing the reinforcement stiffness matrix * along with the reinforcement residual. Room is made for constitutive law, * but actual use of contitutive laws is made in MaterialReinforcementTemplate. * * Be careful with the dimensions in this class : * - this->spatial_dimension is always 1 * - the template parameter dim is the dimension of the problem */ template class MaterialReinforcement : virtual public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// Constructor MaterialReinforcement(SolidMechanicsModel & model, UInt spatial_dimension, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); /// Destructor virtual ~MaterialReinforcement(); protected: void initialize(SolidMechanicsModel & a_model); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Init the material virtual void initMaterial(); /// Init the background shape derivatives void initBackgroundShapeDerivatives(); /// Init the cosine matrices void initDirectingCosines(); /// Assemble stiffness matrix virtual void assembleStiffnessMatrix(GhostType ghost_type); /// Update the residual virtual void updateResidual(GhostType ghost_type = _not_ghost); /// Assembled the residual virtual void assembleResidual(GhostType ghost_type); /// Compute all the stresses ! virtual void computeAllStresses(GhostType ghost_type); /// Compute the stiffness parameter for elements of a type virtual void computeTangentModuli(const ElementType & type, Array & tangent, GhostType ghost_type) = 0; /// Compute energy virtual Real getEnergy(std::string id); - virtual ElementTypeMap getInternalDataPerElem(const ID & field_name, - const ElementKind & kind, - const ID & fe_engine_id) const; - - /// Reimplementation of Material's function to accomodate for interface mesh - virtual void flattenInternal(const std::string & field_id, - ElementTypeMapArray & internal_flat, - const GhostType ghost_type = _not_ghost, - ElementKind element_kind = _ek_not_defined) const; + // virtual ElementTypeMap getInternalDataPerElem(const ID & field_name, + // const ElementKind & kind, + // const ID & fe_engine_id) const; + + // /// Reimplementation of Material's function to accomodate for interface mesh + // virtual void flattenInternal(const std::string & field_id, + // ElementTypeMapArray & internal_flat, + // const GhostType ghost_type = _not_ghost, + // ElementKind element_kind = _ek_not_defined) const; /* ------------------------------------------------------------------------ */ /* Protected methods */ /* ------------------------------------------------------------------------ */ protected: /// Allocate the background shape derivatives void allocBackgroundShapeDerivatives(); /// Compute the directing cosines matrix for one element type void computeDirectingCosines(const ElementType & type, GhostType ghost_type); /// Compute the directing cosines matrix on quadrature points. inline void computeDirectingCosinesOnQuad(const Matrix & nodes, Matrix & cosines); /// Assemble the stiffness matrix for an element type (typically _segment_2) void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// Assemble the stiffness matrix for background & interface types void assembleStiffnessMatrixInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type); /// Compute the background shape derivatives for a type void computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type); /// Filter elements crossed by interface of a type void filterInterfaceBackgroundElements(Array & filter, const ElementType & type, const ElementType & interface_type, GhostType ghost_type); /// Assemble the residual of one type of element (typically _segment_2) void assembleResidual(const ElementType & type, GhostType ghost_type); /// Assemble the residual for a pair of elements void assembleResidualInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type); // TODO figure out why voigt size is 4 in 2D inline void stressTensorToVoigtVector(const Matrix & tensor, Vector & vector); inline void strainTensorToVoigtVector(const Matrix & tensor, Vector & vector); /// Compute gradu on the interface quadrature points virtual void computeGradU(const ElementType & type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Embedded model EmbeddedInterfaceModel * model; /// Stress in the reinforcement InternalField stress_embedded; /// Gradu of concrete on reinforcement InternalField gradu_embedded; /// C matrix on quad InternalField directing_cosines; /// Prestress on quad InternalField pre_stress; /// Cross-sectional area Real area; /// Background mesh shape derivatives ElementTypeMap< ElementTypeMapArray * > shape_derivatives; }; #include "material_reinforcement_inline_impl.cc" __END_AKANTU__ #endif // __AKANTU_MATERIAL_REINFORCEMENT_HH__ diff --git a/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh b/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh index 4c4babf1e..176e36e85 100644 --- a/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh +++ b/src/model/solid_mechanics/materials/random_internal_field_tmpl.hh @@ -1,129 +1,125 @@ /** * @file random_internal_field_tmpl.hh * * @author Nicolas Richart * * @date creation: Wed Nov 13 2013 * @date last modification: Wed Nov 13 2013 * * @brief Random internal material parameter implementation * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_random_generator.hh" #include "internal_field_tmpl.hh" /* -------------------------------------------------------------------------- */ - #ifndef __AKANTU_RANDOM_INTERNAL_FIELD_TMPL_HH__ #define __AKANTU_RANDOM_INTERNAL_FIELD_TMPL_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -template class BaseField, - template class Generator> -RandomInternalField::RandomInternalField(const ID & id, Material & material) : - BaseField(id, material), random_parameter(T()) { -} +template class BaseField, + template class Generator> +RandomInternalField::RandomInternalField( + const ID & id, Material & material) + : BaseField(id, material), random_parameter(T()) {} /* -------------------------------------------------------------------------- */ -template class BaseField, - template class Generator> -RandomInternalField::~RandomInternalField() { } +template class BaseField, + template class Generator> +RandomInternalField::~RandomInternalField() {} /* -------------------------------------------------------------------------- */ -template class BaseField, - template class Generator> -void RandomInternalField::initialize(UInt nb_component) { +template class BaseField, + template class Generator> +void RandomInternalField::initialize( + UInt nb_component) { this->internalInitialize(nb_component); } /* ------------------------------------------------------------------------ */ -template class BaseField, - template class Generator> -void RandomInternalField::setDefaultValue(const T &value) { +template class BaseField, + template class Generator> +void RandomInternalField::setDefaultValue( + const T & value) { random_parameter.setBaseValue(value); this->reset(); } /* ------------------------------------------------------------------------ */ -template class BaseField, - template class Generator> -void RandomInternalField::setRandomDistribution(const RandomParameter & param) { +template class BaseField, + template class Generator> +void RandomInternalField::setRandomDistribution( + const RandomParameter & param) { random_parameter = param; this->reset(); } /* ------------------------------------------------------------------------ */ -template class BaseField, - template class Generator> -void RandomInternalField::printself(std::ostream & stream, unsigned int indent) const { +template class BaseField, + template class Generator> +void RandomInternalField::printself( + std::ostream & stream, unsigned int indent) const { stream << "RandomInternalField [ "; random_parameter.printself(stream); stream << " ]"; #if !defined(AKANTU_NDEBUG) - if(AKANTU_DEBUG_TEST(dblDump)) { + if (AKANTU_DEBUG_TEST(dblDump)) { stream << std::endl; InternalField::printself(stream, indent); } #endif } /* -------------------------------------------------------------------------- */ -template class BaseField, - template class Generator> -void RandomInternalField::setArrayValues(T * begin, T * end) { +template class BaseField, + template class Generator> +void RandomInternalField::setArrayValues(T * begin, + T * end) { random_parameter.template setValues(begin, end); } /* -------------------------------------------------------------------------- */ -template class BaseField, - template class Generator> +template class BaseField, + template class Generator> inline RandomInternalField::operator Real() const { return random_parameter.getBaseValue(); } /* -------------------------------------------------------------------------- */ -template<> -inline void ParsableParamTyped< RandomInternalField >::parseParam(const ParserParameter & in_param) { +template <> +inline void ParsableParamTyped >::parseParam( + const ParserParameter & in_param) { ParsableParam::parseParam(in_param); RandomParameter r = in_param; param.setRandomDistribution(r); } /* -------------------------------------------------------------------------- */ - __END_AKANTU__ #endif /* __AKANTU_RANDOM_INTERNAL_FIELD_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index 22a7e4ebe..02c3553d5 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1827 +1,1832 @@ /** * @file solid_mechanics_model.cc * * @author Guillaume Anciaux * @author David Simon Kammer * @author Aurelia Isabel Cuba Ramos * @author Daniel Pino Muñoz * @author Nicolas Richart * * @date creation: Tue Jul 27 2010 * @date last modification: Fri Sep 19 2014 * * @brief Implementation of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_math.hh" #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "group_manager_inline_impl.cc" #include "dumpable_inline_impl.hh" #include "integration_scheme_2nd_order.hh" #include "element_group.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" #include "element_group.hh" #include #ifdef AKANTU_USE_MUMPS #include "solver_mumps.hh" #endif #ifdef AKANTU_USE_PETSC #include "solver_petsc.hh" #include "petsc_matrix.hh" #endif #ifdef AKANTU_USE_IOHELPER # include "dumper_field.hh" # include "dumper_paraview.hh" # include "dumper_homogenizing_field.hh" # include "dumper_internal_material_field.hh" # include "dumper_elemental_field.hh" # include "dumper_material_padders.hh" # include "dumper_element_partition.hh" # include "dumper_iohelper.hh" #endif #ifdef AKANTU_DAMAGE_NON_LOCAL # include "non_local_manager.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const SolidMechanicsModelOptions default_solid_mechanics_model_options(_explicit_lumped_mass, false); /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), BoundaryCondition(), time_step(NAN), f_m2a(1.0), mass_matrix(NULL), velocity_damping_matrix(NULL), stiffness_matrix(NULL), jacobian_matrix(NULL), material_index("material index", id), material_local_numbering("material local numbering", id), material_selector(new DefaultMaterialSelector(material_index)), is_default_material_selector(true), integrator(NULL), increment_flag(false), solver(NULL), synch_parallel(NULL), are_materials_instantiated(false), - non_local_manager(NULL) { + non_local_manager(NULL), + pbc_synch(NULL) { AKANTU_DEBUG_IN(); createSynchronizerRegistry(this); registerFEEngineObject("SolidMechanicsFEEngine", mesh, spatial_dimension); this->displacement = NULL; this->mass = NULL; this->velocity = NULL; this->acceleration = NULL; this->force = NULL; this->residual = NULL; this->blocked_dofs = NULL; this->increment = NULL; this->increment_acceleration = NULL; this->dof_synchronizer = NULL; this->previous_displacement = NULL; materials.clear(); mesh.registerEventHandler(*this); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper("paraview_all", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { delete *mat_it; } materials.clear(); delete integrator; delete solver; delete mass_matrix; delete velocity_damping_matrix; if(stiffness_matrix && stiffness_matrix != jacobian_matrix) delete stiffness_matrix; delete jacobian_matrix; delete synch_parallel; if(is_default_material_selector) { delete material_selector; material_selector = NULL; } #ifdef AKANTU_DAMAGE_NON_LOCAL delete non_local_manager; non_local_manager = NULL; #endif + delete pbc_synch; + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setTimeStep(Real time_step) { this->time_step = time_step; #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilities */ void SolidMechanicsModel::initFull(const ModelOptions & options) { Model::initFull(options); const SolidMechanicsModelOptions & smm_options = dynamic_cast(options); this->method = smm_options.analysis_method; // initialize the vectors this->initArrays(); // set the initial condition to 0 this->force->clear(); this->velocity->clear(); this->acceleration->clear(); this->displacement->clear(); // initialize pbc if(this->pbc_pair.size()!=0) this->initPBC(); // initialize the time integration schemes switch(this->method) { case _explicit_lumped_mass: this->initExplicit(); break; case _explicit_consistent_mass: this->initSolver(); this->initExplicit(); break; case _implicit_dynamic: this->initImplicit(true); break; case _static: this->initImplicit(false); this->initArraysPreviousDisplacment(); break; default: AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel"); break; } #ifdef AKANTU_DAMAGE_NON_LOCAL /// create the non-local manager object for non-local damage computations this->non_local_manager = new NonLocalManager(*this); #endif // initialize the materials if(this->parser->getLastParsedFile() != "") { this->instantiateMaterials(); } if(!smm_options.no_init_materials) { this->initMaterials(); } if(this->increment_flag) this->initBC(*this, *this->displacement, *this->increment, *this->force); else this->initBC(*this, *this->displacement, *this->force); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initParallel(MeshPartition * partition, DataAccessor * data_accessor) { AKANTU_DEBUG_IN(); if (data_accessor == NULL) data_accessor = this; synch_parallel = &createParallelSynch(partition,data_accessor); synch_registry->registerSynchronizer(*synch_parallel, _gst_material_id); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_mass); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_stress); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_boundary); synch_registry->registerSynchronizer(*synch_parallel, _gst_for_dump); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_not_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initExplicit(AnalysisMethod analysis_method) { AKANTU_DEBUG_IN(); //in case of switch from implicit to explicit if(!this->isExplicit()) method = analysis_method; if (integrator) delete integrator; integrator = new CentralDifference(); UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); std::stringstream sstr; sstr << id << ":increment_acceleration"; increment_acceleration = &(alloc(sstr.str(), nb_nodes, nb_degree_of_freedom, Real())); AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initArraysPreviousDisplacment() { AKANTU_DEBUG_IN(); this->setIncrementFlagOn(); - UInt nb_nodes = this->mesh.getNbNodes(); - std::stringstream sstr_disp_t; - sstr_disp_t << this->id << ":previous_displacement"; - this->previous_displacement = &(this->alloc (sstr_disp_t.str(), nb_nodes, this->spatial_dimension, 0.)); + if(not this->previous_displacement) { + UInt nb_nodes = this->mesh.getNbNodes(); + std::stringstream sstr_disp_t; + sstr_disp_t << this->id << ":previous_displacement"; + + this->previous_displacement = &(this->alloc (sstr_disp_t.str(), nb_nodes, this->spatial_dimension, 0.)); + } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Allocate all the needed vectors. By default their are not necessarily set to * 0 * */ void SolidMechanicsModel::initArrays() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":displacement"; // std::stringstream sstr_mass; sstr_mass << id << ":mass"; std::stringstream sstr_velo; sstr_velo << id << ":velocity"; std::stringstream sstr_acce; sstr_acce << id << ":acceleration"; std::stringstream sstr_forc; sstr_forc << id << ":force"; std::stringstream sstr_resi; sstr_resi << id << ":residual"; std::stringstream sstr_boun; sstr_boun << id << ":blocked_dofs"; displacement = &(alloc(sstr_disp.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); // mass = &(alloc(sstr_mass.str(), nb_nodes, spatial_dimension, 0)); velocity = &(alloc(sstr_velo.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); acceleration = &(alloc(sstr_acce.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); force = &(alloc(sstr_forc.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); residual = &(alloc(sstr_resi.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); blocked_dofs = &(alloc(sstr_boun.str(), nb_nodes, spatial_dimension, false)); std::stringstream sstr_curp; sstr_curp << id << ":current_position"; current_position = &(alloc(sstr_curp.str(), 0, spatial_dimension, REAL_INIT_VALUE)); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, gt); material_index.alloc(nb_element, 1, *it, gt); material_local_numbering.alloc(nb_element, 1, *it, gt); } } dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian * */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initPBC() { Model::initPBC(); registerPBCSynchronizer(); // as long as there are ones on the diagonal of the matrix, we can put boudandary true for slaves std::map::iterator it = pbc_pair.begin(); std::map::iterator end = pbc_pair.end(); UInt dim = mesh.getSpatialDimension(); while(it != end) { for (UInt i=0; iregisterSynchronizer(*synch, _gst_smm_uv); - synch_registry->registerSynchronizer(*synch, _gst_smm_mass); - synch_registry->registerSynchronizer(*synch, _gst_smm_res); - synch_registry->registerSynchronizer(*synch, _gst_for_dump); + pbc_synch = new PBCSynchronizer(pbc_pair); + synch_registry->registerSynchronizer(*pbc_synch, _gst_smm_uv); + synch_registry->registerSynchronizer(*pbc_synch, _gst_smm_mass); + synch_registry->registerSynchronizer(*pbc_synch, _gst_smm_res); + synch_registry->registerSynchronizer(*pbc_synch, _gst_for_dump); changeLocalEquationNumberForPBC(pbc_pair, mesh.getSpatialDimension()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); current_position->resize(nb_nodes); Real * current_position_val = current_position->storage(); Real * position_val = mesh.getNodes().storage(); Real * displacement_val = displacement->storage(); /// compute current_position = initial_position + displacement memcpy(current_position_val, position_val, nb_nodes*spatial_dimension*sizeof(Real)); for (UInt n = 0; n < nb_nodes*spatial_dimension; ++n) { *current_position_val++ += *displacement_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeUpdateResidualData() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); residual->resize(nb_nodes); /// copy the forces in residual for boundary conditions memcpy(residual->storage(), force->storage(), nb_nodes*spatial_dimension*sizeof(Real)); // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); updateCurrentPosition(); AKANTU_DEBUG_OUT(); } /*----------------------------------------------------------------------------*/ void SolidMechanicsModel::reInitialize() { } /* -------------------------------------------------------------------------- */ /* Explicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * This function compute the second member of the motion equation. That is to * say the sum of forces @f$ r = F_{ext} - F_{int} @f$. @f$ F_{ext} @f$ is given * by the user in the force vector, and @f$ F_{int} @f$ is computed as @f$ * F_{int} = \int_{\Omega} N \sigma d\Omega@f$ * */ void SolidMechanicsModel::updateResidual(bool need_initialize) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); // f = f_ext - f_int // f = f_ext if(need_initialize) initializeUpdateResidualData(); AKANTU_DEBUG_INFO("Compute local stresses"); std::vector::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } #ifdef AKANTU_DAMAGE_NON_LOCAL /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ this->non_local_manager->computeAllNonLocalStresses(); #endif /* ------------------------------------------------------------------------ */ /* assembling the forces internal */ // communicate the stress AKANTU_DEBUG_INFO("Send data for residual assembly"); synch_registry->asynchronousSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for local elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_not_ghost); } AKANTU_DEBUG_INFO("Wait distant stresses"); // finalize communications synch_registry->waitEndSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeStresses() { if (isExplicit()) { // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); // compute stresses on all local elements for each materials std::vector::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ #ifdef AKANTU_DAMAGE_NON_LOCAL /* Computation of the non local part */ this->non_local_manager->computeAllNonLocalStresses(); #endif } else { std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStressesFromTangentModuli(_not_ghost); } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateResidualInternal() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Update the residual"); // f = f_ext - f_int - Ma - Cv = r - Ma - Cv; if(method != _static) { // f -= Ma if(mass_matrix) { // if full mass_matrix Array * Ma = new Array(*acceleration, true, "Ma"); *Ma *= *mass_matrix; /// \todo check unit conversion for implicit dynamics // *Ma /= f_m2a *residual -= *Ma; delete Ma; } else if (mass) { // else lumped mass UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); Real * mass_val = mass->storage(); Real * accel_val = acceleration->storage(); Real * res_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *res_val -= *accel_val * *mass_val /f_m2a; } blocked_dofs_val++; res_val++; mass_val++; accel_val++; } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } // f -= Cv if(velocity_damping_matrix) { Array * Cv = new Array(*velocity); *Cv *= *velocity_damping_matrix; *residual -= *Cv; delete Cv; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateAcceleration() { AKANTU_DEBUG_IN(); updateResidualInternal(); if(method == _explicit_lumped_mass) { /* residual = residual_{n+1} - M * acceleration_n therefore solution = increment acceleration not acceleration */ solveLumped(*increment_acceleration, *mass, *residual, *blocked_dofs, f_m2a); } else if (method == _explicit_consistent_mass) { solve(*increment_acceleration); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveLumped(Array & x, const Array & A, const Array & b, const Array & blocked_dofs, Real alpha) { Real * A_val = A.storage(); Real * b_val = b.storage(); Real * x_val = x.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); UInt nb_degrees_of_freedom = x.getSize() * x.getNbComponent(); for (UInt n = 0; n < nb_degrees_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *x_val = alpha * (*b_val / *A_val); } x_val++; A_val++; b_val++; blocked_dofs_val++; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitPred() { AKANTU_DEBUG_IN(); if(increment_flag) { if(previous_displacement) increment->copy(*previous_displacement); else increment->copy(*displacement); } AKANTU_DEBUG_ASSERT(integrator,"itegrator should have been allocated: " << "have called initExplicit ? " << "or initImplicit ?"); integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); if(increment_flag) { Real * inc_val = increment->storage(); Real * dis_val = displacement->storage(); UInt nb_degree_of_freedom = displacement->getSize() * displacement->getNbComponent(); for (UInt n = 0; n < nb_degree_of_freedom; ++n) { *inc_val = *dis_val - *inc_val; inc_val++; dis_val++; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitCorr() { AKANTU_DEBUG_IN(); integrator->integrationSchemeCorrAccel(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment_acceleration); if(previous_displacement) previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveStep() { AKANTU_DEBUG_IN(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); this->explicitPred(); this->updateResidual(); this->updateAcceleration(); this->explicitCorr(); EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Implicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * Initialize the solver and create the sparse matrices needed. * */ void SolidMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) { #if !defined(AKANTU_USE_MUMPS) && !defined(AKANTU_USE_PETSC)// or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake AKANTU_DEBUG_ERROR("You should at least activate one solver."); #else UInt nb_global_nodes = mesh.getNbGlobalNodes(); delete jacobian_matrix; std::stringstream sstr; sstr << id << ":jacobian_matrix"; #ifdef AKANTU_USE_PETSC jacobian_matrix = new PETScMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); #else jacobian_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); #endif //AKANTU_USE PETSC jacobian_matrix->buildProfile(mesh, *dof_synchronizer, spatial_dimension); if (!isExplicit()) { delete stiffness_matrix; std::stringstream sstr_sti; sstr_sti << id << ":stiffness_matrix"; #ifdef AKANTU_USE_PETSC stiffness_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); stiffness_matrix->buildProfile(mesh, *dof_synchronizer, spatial_dimension); #else stiffness_matrix = new SparseMatrix(*jacobian_matrix, sstr_sti.str(), memory_id); #endif //AKANTU_USE_PETSC } delete solver; std::stringstream sstr_solv; sstr_solv << id << ":solver"; #ifdef AKANTU_USE_PETSC solver = new SolverPETSc(*jacobian_matrix, sstr_solv.str()); #elif defined(AKANTU_USE_MUMPS) solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS if(solver) solver->initialize(options); #endif //AKANTU_HAS_SOLVER } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initJacobianMatrix() { #if defined(AKANTU_USE_MUMPS) && !defined(AKANTU_USE_PETSC) // @todo make it more flexible: this is an ugly patch to treat the case of non // fix profile of the K matrix delete jacobian_matrix; std::stringstream sstr_sti; sstr_sti << id << ":jacobian_matrix"; jacobian_matrix = new SparseMatrix(*stiffness_matrix, sstr_sti.str(), memory_id); std::stringstream sstr_solv; sstr_solv << id << ":solver"; delete solver; solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); if(solver) solver->initialize(_solver_no_options); #else AKANTU_DEBUG_ERROR("You need to activate the solver mumps."); #endif } /* -------------------------------------------------------------------------- */ /** * Initialize the implicit solver, either for dynamic or static cases, * * @param dynamic */ void SolidMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); method = dynamic ? _implicit_dynamic : _static; if (!increment) setIncrementFlagOn(); initSolver(solver_options); if(method == _implicit_dynamic) { if(integrator) delete integrator; integrator = new TrapezoidalRule2(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initialAcceleration() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving Ma = f"); Solver * acc_solver = NULL; std::stringstream sstr; sstr << id << ":tmp_mass_matrix"; SparseMatrix * tmp_mass = new SparseMatrix(*mass_matrix, sstr.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solver; sstr << id << ":solver_mass_matrix"; acc_solver = new SolverMumps(*mass_matrix, sstr_solver.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS acc_solver->initialize(); tmp_mass->applyBoundary(*blocked_dofs); acc_solver->setRHS(*residual); acc_solver->solve(*acceleration); delete acc_solver; delete tmp_mass; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); stiffness_matrix->clear(); // call compute stiffness matrix on each local elements std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->assembleStiffnessMatrix(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix & SolidMechanicsModel::initVelocityDampingMatrix() { if(!velocity_damping_matrix) velocity_damping_matrix = new SparseMatrix(*jacobian_matrix, id + ":velocity_damping_matrix", memory_id); return *velocity_damping_matrix; } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_increment>(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); Real * displacement_val = displacement->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val) && is_local_node) { norm[0] += *increment_val * *increment_val; norm[1] += *displacement_val * *displacement_val; } blocked_dofs_val++; increment_val++; displacement_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum); norm[0] = sqrt(norm[0]); norm[1] = sqrt(norm[1]); AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something goes wrong in the solve phase"); if (norm[1] < Math::getTolerance()) { error = norm[0]; AKANTU_DEBUG_OUT(); // cout<<"Error 1: "< Math::getTolerance()) error = norm[0] / norm[1]; else error = norm[0]; //In case the total displacement is zero! // cout<<"Error 2: "< bool SolidMechanicsModel::testConvergence<_scc_residual>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent(); norm = 0; Real * residual_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val; } blocked_dofs_val++; residual_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_residual_mass_wgh>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->storage(); Real * mass_val = this->mass->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < spatial_dimension; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val/(*mass_val * *mass_val); } blocked_dofs_val++; residual_val++; mass_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; mass_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitPred() { AKANTU_DEBUG_IN(); if(method == _implicit_dynamic) integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitCorr() { AKANTU_DEBUG_IN(); if(method == _implicit_dynamic) { integrator->integrationSchemeCorrDispl(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment); } else { UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); bool * boun_val = blocked_dofs->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++boun_val){ *incr_val *= (1. - *boun_val); *disp_val += *incr_val; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateIncrement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); Real * prev_disp_val = previous_displacement->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++prev_disp_val) *incr_val = (*disp_val - *prev_disp_val); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updatePreviousDisplacement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeBoundaries() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initParallel?"); synch_registry->synchronize(_gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeResidual() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initPBC?"); synch_registry->synchronize(_gst_smm_res); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setIncrementFlagOn() { AKANTU_DEBUG_IN(); if(!increment) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_inc; sstr_inc << id << ":increment"; increment = &(alloc(sstr_inc.str(), nb_nodes, spatial_dimension, 0.)); } increment_flag = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors StaticCommunicator::getStaticCommunicator().allReduce(&min_dt, 1, _so_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Material ** mat_val = &(materials.at(0)); Real min_dt = std::numeric_limits::max(); updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; elem.kind = _ek_regular; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_regular); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type, _ek_regular); for(; it != end; ++it) { elem.type = *it; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); UInt nb_element = mesh.getNbElement(*it); Array::const_scalar_iterator mat_indexes = material_index(*it, ghost_type).begin(); Array::const_scalar_iterator mat_loc_num = material_local_numbering(*it, ghost_type).begin(); Array X(0, nb_nodes_per_element*spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, *it, _not_ghost); Array::matrix_iterator X_el = X.begin(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, *it); Real el_c = mat_val[*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(); if (!mass && !mass_matrix) AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); Real * vel_val = velocity->storage(); Real * mass_val = mass->storage(); for (UInt n = 0; n < nb_nodes; ++n) { 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; for (UInt i = 0; i < spatial_dimension; ++i) { if (count_node) mv2 += *vel_val * *vel_val * *mass_val; vel_val++; mass_val++; } ekin += mv2; } StaticCommunicator::getStaticCommunicator().allReduce(&ekin, 1, _so_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); Array vel_on_quad(nb_quadrature_points, spatial_dimension); Array filter_element(1, 1, index); getFEEngine().interpolateOnIntegrationPoints(*velocity, vel_on_quad, spatial_dimension, type, _not_ghost, filter_element); Array::vector_iterator vit = vel_on_quad.begin(spatial_dimension); Array::vector_iterator vend = vel_on_quad.end(spatial_dimension); Vector 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(); Real * incr_or_velo = NULL; if(this->method == _static){ incr_or_velo = this->increment->storage(); } else incr_or_velo = this->velocity->storage(); Real * forc = this->force->storage(); Real * resi = this->residual->storage(); bool * boun = this->blocked_dofs->storage(); Real work = 0.; UInt nb_nodes = this->mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { 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; for (UInt i = 0; i < this->spatial_dimension; ++i) { if (count_node) { if(*boun) work -= *resi * *incr_or_velo; else work += *forc * *incr_or_velo; } ++incr_or_velo; ++forc; ++resi; ++boun; } } StaticCommunicator::getStaticCommunicator().allReduce(&work, 1, _so_sum); if(this->method != _static) work *= this->time_step; 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.; std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getEnergy(energy_id); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_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); } std::vector::iterator mat_it; 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_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = this->mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = this->mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = this->mesh.getNbElement(*it, gt); if(!material_index.exists(*it, gt)) { this->material_index .alloc(nb_element, 1, *it, gt); this->material_local_numbering.alloc(nb_element, 1, *it, gt); } else { this->material_index (*it, gt).resize(nb_element); this->material_local_numbering(*it, gt).resize(nb_element); } } } Array::const_iterator it = element_list.begin(); Array::const_iterator end = element_list.end(); ElementTypeMapArray filter("new_element_filter", this->getID()); for (UInt el = 0; it != end; ++it, ++el) { const Element & elem = *it; 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); std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsAdded(element_list, event); } if(method == _explicit_lumped_mass) this->assembleMassLumped(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved(__attribute__((unused)) const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) { this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array & nodes_list, __attribute__((unused)) const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if(displacement) displacement->resize(nb_nodes); if(mass ) mass ->resize(nb_nodes); if(velocity ) velocity ->resize(nb_nodes); if(acceleration) acceleration->resize(nb_nodes); if(force ) force ->resize(nb_nodes); if(residual ) residual ->resize(nb_nodes); if(blocked_dofs) blocked_dofs->resize(nb_nodes); if(previous_displacement) previous_displacement->resize(nb_nodes); if(increment_acceleration) increment_acceleration->resize(nb_nodes); if(increment) increment->resize(nb_nodes); if(current_position) current_position->resize(nb_nodes); std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onNodesAdded(nodes_list, event); } delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); if (method != _explicit_lumped_mass) { this->initSolver(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesRemoved(__attribute__((unused)) const Array & element_list, const Array & new_numbering, __attribute__((unused)) const RemovedNodesEvent & event) { if(displacement) mesh.removeNodesFromArray(*displacement, new_numbering); if(mass ) mesh.removeNodesFromArray(*mass , new_numbering); if(velocity ) mesh.removeNodesFromArray(*velocity , new_numbering); if(acceleration) mesh.removeNodesFromArray(*acceleration, new_numbering); if(force ) mesh.removeNodesFromArray(*force , new_numbering); if(residual ) mesh.removeNodesFromArray(*residual , new_numbering); if(blocked_dofs) mesh.removeNodesFromArray(*blocked_dofs, new_numbering); if(increment_acceleration) mesh.removeNodesFromArray(*increment_acceleration, new_numbering); if(increment) mesh.removeNodesFromArray(*increment , new_numbering); delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); if (method != _explicit_lumped_mass) { this->initSolver(); } } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::isInternal(const std::string & field_name, - const ElementKind & element_kind){ + const ElementKind & element_kind) { bool is_internal = false; /// check if at least one material contains field_id as an internal for (UInt m = 0; m < materials.size() && !is_internal; ++m) { - is_internal |= materials[m]->isInternal(field_name, element_kind); + is_internal |= materials[m]->isInternal(field_name, element_kind); } return is_internal; } /* -------------------------------------------------------------------------- */ +ElementTypeMap +SolidMechanicsModel::getInternalDataPerElem(const std::string & field_name, + const ElementKind & element_kind) { -ElementTypeMap SolidMechanicsModel::getInternalDataPerElem(const std::string & field_name, - const ElementKind & element_kind){ - - - if (!(this->isInternal(field_name,element_kind))) AKANTU_EXCEPTION("unknown internal " << field_name); + if (!(this->isInternal(field_name, element_kind))) + AKANTU_EXCEPTION("unknown internal " << field_name); - for (UInt m = 0; m < materials.size() ; ++m) { - if (materials[m]->isInternal(field_name, element_kind)) - return materials[m]->getInternalDataPerElem(field_name, element_kind); + for (UInt m = 0; m < materials.size(); ++m) { + if (materials[m]->isInternal(field_name, element_kind)) + return materials[m]->getInternalDataPerElem(field_name, element_kind); } return ElementTypeMap(); } - /* -------------------------------------------------------------------------- */ -ElementTypeMapArray & SolidMechanicsModel::flattenInternal(const std::string & field_name, - const ElementKind & kind, - const GhostType ghost_type){ - std::pair key(field_name,kind); - if (this->registered_internals.count(key) == 0){ +ElementTypeMapArray & +SolidMechanicsModel::flattenInternal(const std::string & field_name, + const ElementKind & kind, + const GhostType ghost_type) { + std::pair key(field_name, kind); + if (this->registered_internals.count(key) == 0) { this->registered_internals[key] = - new ElementTypeMapArray(field_name, this->id); + new ElementTypeMapArray(field_name, this->id); } ElementTypeMapArray * internal_flat = this->registered_internals[key]; typedef ElementTypeMapArray::type_iterator iterator; - iterator tit = internal_flat->firstType(spatial_dimension, - ghost_type, - kind); - iterator end = internal_flat->lastType(spatial_dimension, - ghost_type, - kind); + iterator tit = internal_flat->firstType(spatial_dimension, ghost_type, kind); + iterator end = internal_flat->lastType(spatial_dimension, ghost_type, kind); for (; tit != end; ++tit) { ElementType type = *tit; - (*internal_flat)(type,ghost_type).clear(); + (*internal_flat)(type, ghost_type).clear(); } - + for (UInt m = 0; m < materials.size(); ++m) { - if (materials[m]->isInternal(field_name, kind)) - materials[m]->flattenInternal(field_name, *internal_flat, ghost_type, kind); + if (materials[m]->isInternal(field_name, kind)) + materials[m]->flattenInternal(field_name, *internal_flat, ghost_type, + kind); } - return *internal_flat; + return *internal_flat; } /* -------------------------------------------------------------------------- */ -void SolidMechanicsModel::flattenAllRegisteredInternals(const ElementKind & kind){ +void SolidMechanicsModel::flattenAllRegisteredInternals( + const ElementKind & kind) { - std::map, - ElementTypeMapArray *>::iterator it = this->registered_internals.begin(); - std::map, - ElementTypeMapArray *>::iterator end = this->registered_internals.end(); + typedef std::map, + ElementTypeMapArray *>::iterator iterator; + iterator it = this->registered_internals.begin(); + iterator end = this->registered_internals.end(); - while (it != end){ + while (it != end) { if (kind == it->first.second) this->flattenInternal(it->first.first, kind); ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onDump(){ this->flattenAllRegisteredInternals(_ek_regular); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, - const std::string & group_name, - bool padding_flag, - const UInt & spatial_dimension, - const ElementKind & kind) { + const std::string & group_name, + bool padding_flag, + const UInt & spatial_dimension, + const ElementKind & kind) { dumper::Field * field = NULL; if(field_name == "partitions") field = mesh.createElementalField(mesh.getConnectivities(),group_name,spatial_dimension,kind); else if(field_name == "material_index") field = mesh.createElementalField(material_index,group_name,spatial_dimension,kind); else { // this copy of field_name is used to compute derivated data such as // strain and von mises stress that are based on grad_u and stress std::string field_name_copy(field_name); if (field_name == "strain" || field_name == "Green strain" || field_name == "principal strain" || field_name == "principal Green strain") field_name_copy = "grad_u"; else if (field_name == "Von Mises stress") field_name_copy = "stress"; bool is_internal = this->isInternal(field_name_copy,kind); if (is_internal) { ElementTypeMap nb_data_per_elem = this->getInternalDataPerElem(field_name_copy, kind); ElementTypeMapArray & internal_flat = this->flattenInternal(field_name_copy,kind); field = mesh.createElementalField(internal_flat, group_name, spatial_dimension,kind,nb_data_per_elem); if (field_name == "strain"){ dumper::ComputeStrain * foo = new dumper::ComputeStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "Von Mises stress") { dumper::ComputeVonMisesStress * foo = new dumper::ComputeVonMisesStress(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "Green strain") { dumper::ComputeStrain * foo = new dumper::ComputeStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "principal strain") { dumper::ComputePrincipalStrain * foo = new dumper::ComputePrincipalStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "principal Green strain") { dumper::ComputePrincipalStrain * foo = new dumper::ComputePrincipalStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } //treat the paddings if (padding_flag){ if (field_name == "stress"){ if (spatial_dimension == 2) { dumper::StressPadder<2> * foo = new dumper::StressPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } else if (field_name == "strain" || field_name == "Green strain"){ if (spatial_dimension == 2) { dumper::StrainPadder<2> * foo = new dumper::StrainPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } } // homogenize the field dumper::ComputeFunctorInterface * foo = dumper::HomogenizerProxy::createHomogenizer(*field); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map* > real_nodal_fields; real_nodal_fields["displacement" ] = displacement; real_nodal_fields["mass" ] = mass; real_nodal_fields["velocity" ] = velocity; real_nodal_fields["acceleration" ] = acceleration; real_nodal_fields["force" ] = force; real_nodal_fields["residual" ] = residual; real_nodal_fields["increment" ] = increment; dumper::Field * field = NULL; if (padding_flag) field = mesh.createNodalField(real_nodal_fields[field_name], group_name, 3); else field = mesh.createNodalField(real_nodal_fields[field_name], group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map* > uint_nodal_fields; uint_nodal_fields["blocked_dofs" ] = blocked_dofs; dumper::Field * field = NULL; field = mesh.createNodalField(uint_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ #else /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & kind){ return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump() { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeCauchyStresses() { AKANTU_DEBUG_IN(); // call compute stiffness matrix on each local elements std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; if(mat.isFiniteDeformation()) mat.computeAllCauchyStresses(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::saveStressAndStrainBeforeDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::BeginningOfDamageIterationEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateEnergiesAfterDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::AfterDamageEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); mass ->printself(stream, indent + 2); velocity ->printself(stream, indent + 2); acceleration->printself(stream, indent + 2); force ->printself(stream, indent + 2); residual ->printself(stream, indent + 2); 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; std::vector::const_iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { const Material & mat = *(*mat_it); mat.printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index e66d21637..f652dac9e 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,762 +1,771 @@ /** * @file solid_mechanics_model.hh * * @author Guillaume Anciaux * @author Daniel Pino Muñoz * @author Nicolas Richart * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Model of Solid Mechanics * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free 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 . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_types.hh" #include "model.hh" #include "data_accessor.hh" #include "mesh.hh" #include "dumpable.hh" #include "boundary_condition.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "integration_scheme_2nd_order.hh" #include "solver.hh" #include "material_selector.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Material; class IntegrationScheme2ndOrder; class SparseMatrix; class DumperIOHelper; class NonLocalManager; } /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ struct SolidMechanicsModelOptions : public ModelOptions { SolidMechanicsModelOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool no_init_materials = false) : analysis_method(analysis_method), no_init_materials(no_init_materials) { } AnalysisMethod analysis_method; bool no_init_materials; }; extern const SolidMechanicsModelOptions default_solid_mechanics_model_options; class SolidMechanicsModel : public Model, public DataAccessor, public MeshEventHandler, public BoundaryCondition, public EventHandlerManager { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewMaterialElementsEvent : public NewElementsEvent { public: AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array &); AKANTU_GET_MACRO(MaterialList, material, const Array &); protected: Array material; }; typedef FEEngineTemplate MyFEEngineType; protected: typedef EventHandlerManager EventManager; public: SolidMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize completely the model virtual void initFull(const ModelOptions & options = default_solid_mechanics_model_options); /// initialize the fem object needed for boundary conditions void initFEEngineBoundary(); /// register the tags associated with the parallel synchronizer virtual void initParallel(MeshPartition *partition, DataAccessor *data_accessor = NULL); /// allocate all vectors virtual void initArrays(); /// allocate all vectors void initArraysPreviousDisplacment(); /// initialize all internal arrays for materials virtual void initMaterials(); /// initialize the model virtual void initModel(); /// init PBC synchronizer void initPBC(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// re-initialize model to set fields to 0 void reInitialize(); /* ------------------------------------------------------------------------ */ /* PBC */ /* ------------------------------------------------------------------------ */ public: /// change the equation number for proper assembly when using PBC // void changeEquationNumberforPBC(std::map & pbc_pair); /// synchronize Residual for output void synchronizeResidual(); protected: /// register PBC synchronizer void registerPBCSynchronizer(); /* ------------------------------------------------------------------------ */ /* Explicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the stuff for the explicit scheme void initExplicit(AnalysisMethod analysis_method = _explicit_lumped_mass); bool isExplicit() { return method == _explicit_lumped_mass || method == _explicit_consistent_mass; } /// initialize the array needed by updateResidual (residual, current_position) void initializeUpdateResidualData(); /// update the current position vector void updateCurrentPosition(); /// assemble the residual for the explicit scheme virtual void updateResidual(bool need_initialize = true); /** * \brief compute the acceleration from the residual * this function is the explicit equivalent to solveDynamic in implicit * In the case of lumped mass just divide the residual by the mass * In the case of not lumped mass call solveDynamic<_acceleration_corrector> */ void updateAcceleration(); void updateIncrement(); void updatePreviousDisplacement(); void saveStressAndStrainBeforeDamage(); void updateEnergiesAfterDamage(); /// Solve the system @f[ A x = \alpha b @f] with A a lumped matrix void solveLumped(Array & x, const Array & A, const Array & b, const Array & blocked_dofs, Real alpha); /// explicit integration predictor void explicitPred(); /// explicit integration corrector void explicitCorr(); public: void solveStep(); /* ------------------------------------------------------------------------ */ /* Implicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver and the jacobian_matrix (called by initImplicit) void initSolver(SolverOptions & options = _solver_no_options); /// initialize the stuff for the implicit solver void initImplicit(bool dynamic = false, SolverOptions & solver_options = _solver_no_options); /// solve Ma = f to get the initial acceleration void initialAcceleration(); /// assemble the stiffness matrix void assembleStiffnessMatrix(); public: /** * solve a step (predictor + convergence loop + corrector) using the * the given convergence method (see akantu::SolveConvergenceMethod) * and the given convergence criteria (see * akantu::SolveConvergenceCriteria) **/ template bool solveStep(Real tolerance, UInt max_iteration = 100); template bool solveStep(Real tolerance, Real & error, UInt max_iteration = 100, bool do_not_factorize = false); public: /** * solve Ku = f using the the given convergence method (see * akantu::SolveConvergenceMethod) and the given convergence * criteria (see akantu::SolveConvergenceCriteria) **/ template bool solveStatic(Real tolerance, UInt max_iteration, bool do_not_factorize = false); /// test if the system is converged template bool testConvergence(Real tolerance, Real & error); /// test the convergence (norm of increment) bool testConvergenceIncrement(Real tolerance) __attribute__((deprecated)); bool testConvergenceIncrement(Real tolerance, Real & error) __attribute__((deprecated)); /// test the convergence (norm of residual) bool testConvergenceResidual(Real tolerance) __attribute__((deprecated)); bool testConvergenceResidual(Real tolerance, Real & error) __attribute__((deprecated)); /// create and return the velocity damping matrix SparseMatrix & initVelocityDampingMatrix(); /// implicit time integration predictor void implicitPred(); /// implicit time integration corrector void implicitCorr(); /// compute the Cauchy stress on user demand. void computeCauchyStresses(); /// compute A and solve @f[ A\delta u = f_ext - f_int @f] template void solve(Array &increment, Real block_val = 1., bool need_factorize = true, bool has_profile_changed = false); protected: /// finish the computation of residual to solve in increment void updateResidualInternal(); /// compute the support reaction and store it in force void updateSupportReaction(); private: /// re-initialize the J matrix (to use if the profile of K changed) void initJacobianMatrix(); /* ------------------------------------------------------------------------ */ /* Explicit/Implicit */ /* ------------------------------------------------------------------------ */ public: /// Update the stresses for the computation of the residual of the Stiffness /// matrix in the case of finite deformation void computeStresses(); /// synchronize the ghost element boundaries values void synchronizeBoundaries(); /* ------------------------------------------------------------------------ */ /* Materials (solid_mechanics_model_material.cc) */ /* ------------------------------------------------------------------------ */ public: /// registers all the custom materials of a given type present in the input file template void registerNewCustomMaterials(const ID & mat_type); /// register an empty material of a given type template Material & registerNewEmptyMaterial(const std::string & name); // /// Use a UIntData in the mesh to specify the material to use per element // void setMaterialIDsFromIntData(const std::string & data_name); /// reassigns materials depending on the material selector virtual void reassignMaterial(); /// apply a constant eigen_grad_u on all quadrature points of a given material virtual void applyEigenGradU(const Matrix & prescribed_eigen_grad_u, const ID & material_name, const GhostType ghost_type = _not_ghost); protected: /// register a material in the dynamic database template Material & registerNewMaterial(const ParserSection & mat_section); /// read the material files to instantiate all the materials void instantiateMaterials(); /// set the element_id_by_material and add the elements to the good materials void assignMaterialToElements(const ElementTypeMapArray * filter = NULL); /* ------------------------------------------------------------------------ */ /* Mass (solid_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); protected: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); /// fill a vector of rho void computeRho(Array & rho, ElementType type, GhostType ghost_type); /// compute the kinetic energy Real getKineticEnergy(); Real getKineticEnergy(const ElementType & type, UInt index); /// compute the external work (for impose displacement, the velocity should be given too) Real getExternalWork(); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline virtual UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const; inline virtual void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const; inline virtual void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag); inline virtual UInt getNbDataToPack(SynchronizationTag tag) const; inline virtual UInt getNbDataToUnpack(SynchronizationTag tag) const; inline virtual void packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const; inline virtual void unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag); protected: inline void splitElementByMaterial(const Array & elements, Array * elements_per_mat) const; /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: virtual void onNodesAdded(const Array & nodes_list, const NewNodesEvent & event); virtual void onNodesRemoved(const Array & element_list, const Array & new_numbering, const RemovedNodesEvent & event); virtual void onElementsAdded(const Array & nodes_list, const NewElementsEvent & event); virtual void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event); + virtual void onElementsChanged(__attribute__((unused)) const Array & old_elements_list, + __attribute__((unused)) const Array & new_elements_list, + __attribute__((unused)) const ElementTypeMapArray & new_numbering, + __attribute__((unused)) const ChangedElementsEvent & event) {}; + + /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ public: virtual void onDump(); //! decide wether a field is a material internal or not bool isInternal(const std::string & field_name, const ElementKind & element_kind); #ifndef SWIG //! give the amount of data per element virtual ElementTypeMap getInternalDataPerElem(const std::string & field_name, const ElementKind & kind); //! flatten a given material internal field ElementTypeMapArray & flattenInternal(const std::string & field_name, const ElementKind & kind, const GhostType ghost_type = _not_ghost); //! flatten all the registered material internals void flattenAllRegisteredInternals(const ElementKind & kind); #endif virtual dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & kind); virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); virtual void dump(); virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the current value of the time step AKANTU_GET_MACRO(TimeStep, time_step, Real); /// set the value of the time step void setTimeStep(Real time_step); /// return the of iterations done in the last solveStep AKANTU_GET_MACRO(NumberIter, n_iter, UInt); /// get the value of the conversion from forces/ mass to acceleration AKANTU_GET_MACRO(F_M2A, f_m2a, Real); /// set the value of the conversion from forces/ mass to acceleration AKANTU_SET_MACRO(F_M2A, f_m2a, Real); /// get the SolidMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array &); /// get the SolidMechanicsModel::previous_displacement vector AKANTU_GET_MACRO(PreviousDisplacement, *previous_displacement, Array &); /// get the SolidMechanicsModel::current_position vector \warn only consistent /// after a call to SolidMechanicsModel::updateCurrentPosition AKANTU_GET_MACRO(CurrentPosition, *current_position, const Array &); /// get the SolidMechanicsModel::increment vector \warn only consistent if /// SolidMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *increment, Array &); /// get the lumped SolidMechanicsModel::mass vector AKANTU_GET_MACRO(Mass, *mass, Array &); /// get the SolidMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array &); /// get the SolidMechanicsModel::acceleration vector, updated by /// SolidMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array &); /// get the SolidMechanicsModel::force vector (boundary forces) AKANTU_GET_MACRO(Force, *force, Array &); /// get the SolidMechanicsModel::residual vector, computed by /// SolidMechanicsModel::updateResidual AKANTU_GET_MACRO(Residual, *residual, Array &); /// get the SolidMechanicsModel::blocked_dofs vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array &); /// get the SolidMechnicsModel::incrementAcceleration vector AKANTU_GET_MACRO(IncrementAcceleration, *increment_acceleration, Array &); /// get the value of the SolidMechanicsModel::increment_flag AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool); /// get a particular material (by material index) inline Material & getMaterial(UInt mat_index); /// get a particular material (by material index) inline const Material & getMaterial(UInt mat_index) const; /// get a particular material (by material name) inline Material & getMaterial(const std::string & name); /// get a particular material (by material name) inline const Material & getMaterial(const std::string & name) const; /// get a particular material id from is name inline UInt getMaterialIndex(const std::string & name) const; /// give the number of materials inline UInt getNbMaterials() const { return materials.size(); } inline void setMaterialSelector(MaterialSelector & selector); /// give the material internal index from its id Int getInternalIndexFromID(const ID & id) const; /// compute the stable time step Real getStableTimeStep(); /// get the energies Real getEnergy(const std::string & energy_id); /// compute the energy for energy Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index); /** * @brief set the SolidMechanicsModel::increment_flag to on, the activate the * update of the SolidMechanicsModel::increment vector */ void setIncrementFlagOn(); /// get the stiffness matrix AKANTU_GET_MACRO(StiffnessMatrix, *stiffness_matrix, SparseMatrix &); /// get the global jacobian matrix of the system AKANTU_GET_MACRO(GlobalJacobianMatrix, *jacobian_matrix, const SparseMatrix &); /// get the mass matrix AKANTU_GET_MACRO(MassMatrix, *mass_matrix, SparseMatrix &); /// get the velocity damping matrix AKANTU_GET_MACRO(VelocityDampingMatrix, *velocity_damping_matrix, SparseMatrix &); /// get the FEEngine object to integrate or interpolate on the boundary inline FEEngine & getFEEngineBoundary(const ID & name = ""); /// get integrator AKANTU_GET_MACRO(Integrator, *integrator, const IntegrationScheme2ndOrder &); /// get access to the internal solver AKANTU_GET_MACRO(Solver, *solver, Solver &); /// get synchronizer AKANTU_GET_MACRO(Synchronizer, *synch_parallel, const DistributedSynchronizer &); AKANTU_GET_MACRO(MaterialByElement, material_index, const ElementTypeMapArray &); /// vectors containing local material element index for each global element index AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialByElement, material_index, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialByElement, material_index, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialLocalNumbering, material_local_numbering, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialLocalNumbering, material_local_numbering, UInt); /// Get the type of analysis method used AKANTU_GET_MACRO(AnalysisMethod, method, AnalysisMethod); /// get the non-local manager AKANTU_GET_MACRO(NonLocalManager, *non_local_manager, NonLocalManager &); template friend struct ContactData; template friend class ContactResolution; protected: friend class Material; protected: /// compute the stable time step Real getStableTimeStep(const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// number of iterations UInt n_iter; /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array *displacement; /// displacements array at the previous time step (used in finite deformation) Array *previous_displacement; /// lumped mass array Array *mass; /// velocities array Array *velocity; /// accelerations array Array *acceleration; /// accelerations array Array *increment_acceleration; /// forces array Array *force; /// residuals array Array *residual; /// array specifing if a degree of freedom is blocked or not Array *blocked_dofs; /// array of current position used during update residual Array *current_position; /// mass matrix SparseMatrix *mass_matrix; /// velocity damping matrix SparseMatrix *velocity_damping_matrix; /// stiffness matrix SparseMatrix *stiffness_matrix; /// jacobian matrix @f[A = cM + dD + K@f] with @f[c = \frac{1}{\beta \Delta /// t^2}, d = \frac{\gamma}{\beta \Delta t} @f] SparseMatrix *jacobian_matrix; /// Arrays containing the material index for each element ElementTypeMapArray material_index; /// Arrays containing the position in the element filter of the material (material's local numbering) ElementTypeMapArray material_local_numbering; #ifdef SWIGPYTHON public: #endif /// list of used materials std::vector materials; /// mapping between material name and material internal id std::map materials_names_to_id; #ifdef SWIGPYTHON protected: #endif /// class defining of to choose a material MaterialSelector *material_selector; /// define if it is the default selector or not bool is_default_material_selector; /// integration scheme of second order used IntegrationScheme2ndOrder *integrator; /// increment of displacement Array *increment; /// flag defining if the increment must be computed or not bool increment_flag; /// solver for implicit Solver *solver; /// analysis method check the list in akantu::AnalysisMethod AnalysisMethod method; /// internal synchronizer for parallel computations DistributedSynchronizer *synch_parallel; /// tells if the material are instantiated bool are_materials_instantiated; /// map a registered internals to be flattened for dump purposes std::map,ElementTypeMapArray *> registered_internals; /// pointer to non-local manager: For non-local continuum damage computations NonLocalManager * non_local_manager; + /// pointer to the pbc synchronizer + PBCSynchronizer * pbc_synch; + }; /* -------------------------------------------------------------------------- */ namespace BC { namespace Neumann { typedef FromHigherDim FromStress; typedef FromSameDim FromTraction; } } __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "material.hh" __BEGIN_AKANTU__ #include "solid_mechanics_model_tmpl.hh" #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "solid_mechanics_model_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator << (std::ostream & stream, const SolidMechanicsModel &_this) { _this.printself(stream); return stream; } __END_AKANTU__ #include "material_selector_tmpl.hh" #endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */ diff --git a/test/test_model/test_non_local_toolbox/CMakeLists.txt b/test/test_model/test_non_local_toolbox/CMakeLists.txt index e619b0771..5e77b6ca9 100644 --- a/test/test_model/test_non_local_toolbox/CMakeLists.txt +++ b/test/test_model/test_non_local_toolbox/CMakeLists.txt @@ -1,62 +1,68 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux # # @date creation: Sun May 01 2011 # @date last modification: Tue Nov 06 2012 # # @brief configuration for heat transfer model tests # # @section LICENSE # # Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free 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 . # # @section DESCRIPTION # #=============================================================================== #=============================================================================== register_test(test_non_local_neighborhood_base SOURCES test_non_local_neighborhood_base.cc test_material.hh test_material.cc FILES_TO_COPY material.dat plot_neighborhoods.py plate.msh PACKAGE damage_non_local ) register_test(test_weight_computation SOURCES test_weight_computation.cc test_material.hh test_material.cc FILES_TO_COPY material_weight_computation.dat plate.msh PACKAGE damage_non_local ) register_test(test_non_local_averaging SOURCES test_non_local_averaging.cc test_material.hh test_material.cc FILES_TO_COPY material_weight_computation.dat plate.msh PACKAGE damage_non_local ) register_test(test_remove_damage_weight_function SOURCES test_remove_damage_weight_function.cc test_material_damage.hh test_material_damage.cc FILES_TO_COPY material_remove_damage.dat plate.msh PACKAGE damage_non_local ) register_test(test_build_neighborhood_parallel - SOURCES test_build_neighborhood_parallel.cc test_material_damage.hh test_material_damage.cc - FILES_TO_COPY material_parallel_test.dat fine_mesh.msh + SOURCES test_build_neighborhood_parallel.cc test_material.hh test_material.cc + FILES_TO_COPY material_parallel_test.dat parallel_test.msh + PACKAGE damage_non_local + ) + +register_test(test_pair_computation + SOURCES test_pair_computation.cc test_material_damage.hh test_material_damage.cc + FILES_TO_COPY material_remove_damage.dat pair_test.msh PACKAGE damage_non_local ) diff --git a/test/test_model/test_non_local_toolbox/material_parallel_test.dat b/test/test_model/test_non_local_toolbox/material_parallel_test.dat index 56980a59a..210e01dec 100644 --- a/test/test_model/test_non_local_toolbox/material_parallel_test.dat +++ b/test/test_model/test_non_local_toolbox/material_parallel_test.dat @@ -1,28 +1,21 @@ material test_material [ name = mat_1 rho = 1 # density E = 1 # young's modulus nu = 0 # poisson's ratio ] material test_material [ name = mat_2 rho = 1 # density E = 1 # young's modulus nu = 0 # poisson's ratio ] - -non_local mat_1 base_wf [ - radius = 0.5 - weight_function weight_parameter [ - update_rate = 1 - ] -] - -non_local mat_2 base_wf [ +non_local test_region remove_wf [ radius = 0.5 weight_function weight_parameter [ - update_rate = 1 + update_rate = 1 + damage_limit = 0.9 ] ] diff --git a/test/test_model/test_non_local_toolbox/pair_test.msh b/test/test_model/test_non_local_toolbox/pair_test.msh new file mode 100644 index 000000000..adf79c73c --- /dev/null +++ b/test/test_model/test_non_local_toolbox/pair_test.msh @@ -0,0 +1,285 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +2 +2 1 "mat_1" +2 2 "mat_2" +$EndPhysicalNames +$Nodes +147 +1 -1 -1 0 +2 0 -1 0 +3 1 -1 0 +4 -1 1 0 +5 0 1 0 +6 1 1 0 +7 -0.8333333333331019 -1 0 +8 -0.6666666666675911 -1 0 +9 -0.5000000000020587 -1 0 +10 -0.3333333333347203 -1 0 +11 -0.1666666666673601 -1 0 +12 0.1666666666663217 -1 0 +13 0.3333333333325025 -1 0 +14 0.4999999999986943 -1 0 +15 0.6666666666657889 -1 0 +16 0.8333333333328945 -1 0 +17 -0.8333333333331019 1 0 +18 -0.6666666666675911 1 0 +19 -0.5000000000020587 1 0 +20 -0.3333333333347203 1 0 +21 -0.1666666666673601 1 0 +22 -1 -0.8000000000005548 0 +23 -1 -0.6000000000011096 0 +24 -1 -0.4000000000016644 0 +25 -1 -0.2000000000022192 0 +26 -1 -2.752242878045763e-12 0 +27 -1 0.1999999999977808 0 +28 -1 0.3999999999983355 0 +29 -1 0.5999999999988903 0 +30 -1 0.7999999999994454 0 +31 0 -0.8000000000005548 0 +32 0 -0.6000000000011096 0 +33 0 -0.4000000000016644 0 +34 0 -0.2000000000022192 0 +35 0 -2.752242878045763e-12 0 +36 0 0.1999999999977808 0 +37 0 0.3999999999983355 0 +38 0 0.5999999999988903 0 +39 0 0.7999999999994454 0 +40 0.1666666666663217 1 0 +41 0.3333333333325025 1 0 +42 0.4999999999986943 1 0 +43 0.6666666666657889 1 0 +44 0.8333333333328945 1 0 +45 1 -0.8000000000005548 0 +46 1 -0.6000000000011096 0 +47 1 -0.4000000000016644 0 +48 1 -0.2000000000022192 0 +49 1 -2.752242878045763e-12 0 +50 1 0.1999999999977808 0 +51 1 0.3999999999983355 0 +52 1 0.5999999999988903 0 +53 1 0.7999999999994454 0 +54 -0.5030532339989087 -0.4604795752809341 0 +55 -0.4991893376216041 -0.2579310797335558 0 +56 -0.4928253212984854 -0.04915482098893964 0 +57 -0.4825167969647393 0.1593831942110211 0 +58 -0.4537131445391057 0.3723675083221218 0 +59 -0.3354763679671945 -0.6495749373148603 0 +60 -0.6720637212240133 -0.6440527727539086 0 +61 -0.8327922142909066 -0.424411789814217 0 +62 -0.1694948826748436 -0.2439216871722153 0 +63 -0.8304654877577068 -0.2263545688411482 0 +64 -0.1676070140031115 -0.03245149868737207 0 +65 -0.8288973697128403 -0.02296850226233027 0 +66 -0.3177756975560099 0.1506226532199915 0 +67 -0.6499513239747395 0.168281999590373 0 +68 -0.332632043786547 0.357209176158553 0 +69 -0.8097098566948024 0.3897528736091556 0 +70 -0.6942802675450694 0.854998657441377 0 +71 -0.3461850865710019 0.8421692582322702 0 +72 -0.5039727684306142 -0.6480714308820643 0 +73 -0.5417691612917842 0.7095854596117401 0 +74 -0.6712440556236705 -0.8238117172557884 0 +75 -0.4095392398396389 0.5279845453194498 0 +76 -0.5861069356184923 0.5558355660389873 0 +77 -0.1857309125373677 0.6523401892267553 0 +78 -0.8349439676325913 -0.6216259170217607 0 +79 -0.7802102628071158 0.6237266553450271 0 +80 -0.5144127730589734 0.8547115964385665 0 +81 -0.6675822792485565 -0.4444452989962474 0 +82 -0.3352489460827015 -0.2600911224288346 0 +83 -0.3374221621912897 -0.4639046570587465 0 +84 -0.3684914749282594 0.6852797329236604 0 +85 -0.5026927486076159 -0.8325836051754552 0 +86 -0.8311761773120493 0.8250586641991118 0 +87 -0.1727521450940143 0.8250426798690156 0 +88 -0.8241972940158289 0.1799786621409103 0 +89 -0.1721159395472645 0.1907669303977386 0 +90 -0.6716244436213226 0.7348369083408823 0 +91 -0.6320795187011508 0.3738573043386093 0 +92 -0.6598292686862797 -0.04213464686197599 0 +93 -0.3303430162643356 -0.0504186782770587 0 +94 -0.2136488293768658 0.4970254941325962 0 +95 -0.6628941913558752 -0.2484656369854851 0 +96 -0.1670116616510103 -0.6300634213566896 0 +97 -0.8360993377658784 -0.8136490127044709 0 +98 -0.165715790497087 -0.81294453704069 0 +99 -0.1687701320665355 -0.4369115603852289 0 +100 -0.3304024146094647 -0.8257352634398845 0 +101 0.497377900174956 -0.4560773336865299 0 +102 0.4988080615949736 -0.2663875869302658 0 +103 0.5050785223400323 -0.05701180906688275 0 +104 0.5158686400624251 0.1548699527023594 0 +105 0.5479694074400454 0.3737343876194663 0 +106 0.6633117489460233 -0.6464584085641401 0 +107 0.3314794870252118 -0.6338404827850097 0 +108 0.1680737454349881 -0.4237359282602401 0 +109 0.8314174022948281 -0.2358261489074746 0 +110 0.1689970784875456 -0.2260911940794778 0 +111 0.8331351238044343 -0.02872858712754478 0 +112 0.1703500751789856 -0.02369232428030787 0 +113 0.6817794215333505 0.1426920479096527 0 +114 0.3486617917953876 0.1661941850090003 0 +115 0.6673679562135154 0.357209176158553 0 +116 0.1786615138291235 0.3881464583742862 0 +117 0.3290488584359573 0.848871509710434 0 +118 0.6552261020460025 0.8413068550720801 0 +119 0.497245429073263 -0.6423454109913329 0 +120 0.4607906126344682 0.7074758864397657 0 +121 0.331666476308289 -0.8184202011724826 0 +122 0.5893203782825908 0.5246371009306479 0 +123 0.4102193202759227 0.5531292234514229 0 +124 0.8142961840162048 0.649742889167632 0 +125 0.1666793877474982 -0.6180944722490216 0 +126 0.2022990824380825 0.619189395677995 0 +127 0.4909473284395671 0.8532569838628081 0 +128 0.3332959984992943 -0.4459043819891003 0 +129 0.6640817912568999 -0.2607101734672508 0 +130 0.6622369248641241 -0.4597222677300552 0 +131 0.63265243918391 0.6835849843356157 0 +132 0.4972910449700644 -0.8310432453089057 0 +133 0.1713211907200942 0.8224535461879088 0 +134 0.82866663878312 0.8252820078498277 0 +135 0.1738363498222202 0.1793980605350007 0 +136 0.827813894920819 0.1893863917079048 0 +137 0.3364814534902554 0.7323669204972425 0 +138 0.3686287965189134 0.3695097298820902 0 +139 0.3392849112652694 -0.043889750338033 0 +140 0.6692420017210666 -0.05191534823397626 0 +141 0.7852589983383298 0.4901695024320518 0 +142 0.3373554832196469 -0.2547720943966668 0 +143 0.8314551357200138 -0.6268873740648218 0 +144 0.1656927329997094 -0.8098568927107836 0 +145 0.8328842890948791 -0.8127159474435377 0 +146 0.8300389178979889 -0.441063907651599 0 +147 0.6660151161336012 -0.8240944407584765 0 +$EndNodes +$Elements +124 +1 3 2 1 6 35 64 62 34 +2 3 2 1 6 26 25 63 65 +3 3 2 1 6 25 24 61 63 +4 3 2 1 6 58 57 66 68 +5 3 2 1 6 59 83 54 72 +6 3 2 1 6 60 74 85 72 +7 3 2 1 6 17 4 30 86 +8 3 2 1 6 21 87 39 5 +9 3 2 1 6 27 26 65 88 +10 3 2 1 6 36 89 64 35 +11 3 2 1 6 88 67 91 69 +12 3 2 1 6 58 91 67 57 +13 3 2 1 6 55 54 83 82 +14 3 2 1 6 72 54 81 60 +15 3 2 1 6 37 94 89 36 +16 3 2 1 6 68 66 89 94 +17 3 2 1 6 75 76 91 58 +18 3 2 1 6 79 69 91 76 +19 3 2 1 6 19 18 70 80 +20 3 2 1 6 19 80 71 20 +21 3 2 1 6 80 70 90 73 +22 3 2 1 6 73 90 79 76 +23 3 2 1 6 76 75 84 73 +24 3 2 1 6 71 80 73 84 +25 3 2 1 6 9 85 74 8 +26 3 2 1 6 29 79 86 30 +27 3 2 1 6 18 17 86 70 +28 3 2 1 6 70 86 79 90 +29 3 2 1 6 38 39 87 77 +30 3 2 1 6 20 71 87 21 +31 3 2 1 6 71 84 77 87 +32 3 2 1 6 81 61 78 60 +33 3 2 1 6 24 23 78 61 +34 3 2 1 6 57 67 92 56 +35 3 2 1 6 88 65 92 67 +36 3 2 1 6 57 56 93 66 +37 3 2 1 6 89 66 93 64 +38 3 2 1 6 58 68 94 75 +39 3 2 1 6 84 75 94 77 +40 3 2 1 6 54 55 95 81 +41 3 2 1 6 61 81 95 63 +42 3 2 1 6 63 95 92 65 +43 3 2 1 6 55 56 92 95 +44 3 2 1 6 62 64 93 82 +45 3 2 1 6 55 82 93 56 +46 3 2 1 6 37 38 77 94 +47 3 2 1 6 69 79 29 28 +48 3 2 1 6 27 88 69 28 +49 3 2 1 6 7 97 22 1 +50 3 2 1 6 23 22 97 78 +51 3 2 1 6 60 78 97 74 +52 3 2 1 6 8 74 97 7 +53 3 2 1 6 34 62 99 33 +54 3 2 1 6 31 32 96 98 +55 3 2 1 6 33 99 96 32 +56 3 2 1 6 62 82 83 99 +57 3 2 1 6 59 96 99 83 +58 3 2 1 6 96 59 100 98 +59 3 2 1 6 9 10 100 85 +60 3 2 1 6 72 85 100 59 +61 3 2 1 6 11 2 31 98 +62 3 2 1 6 10 11 98 100 +63 3 2 2 10 49 111 109 48 +64 3 2 2 10 35 34 110 112 +65 3 2 2 10 34 33 108 110 +66 3 2 2 10 105 104 113 115 +67 3 2 2 10 106 130 101 119 +68 3 2 2 10 107 121 132 119 +69 3 2 2 10 39 133 40 5 +70 3 2 2 10 44 134 53 6 +71 3 2 2 10 36 35 112 135 +72 3 2 2 10 50 136 111 49 +73 3 2 2 10 135 114 138 116 +74 3 2 2 10 105 138 114 104 +75 3 2 2 10 102 101 130 129 +76 3 2 2 10 119 101 128 107 +77 3 2 2 10 51 141 136 50 +78 3 2 2 10 115 113 136 141 +79 3 2 2 10 122 123 138 105 +80 3 2 2 10 126 116 138 123 +81 3 2 2 10 42 127 118 43 +82 3 2 2 10 127 117 137 120 +83 3 2 2 10 120 137 126 123 +84 3 2 2 10 123 122 131 120 +85 3 2 2 10 118 127 120 131 +86 3 2 2 10 14 132 121 13 +87 3 2 2 10 38 126 133 39 +88 3 2 2 10 41 40 133 117 +89 3 2 2 10 117 133 126 137 +90 3 2 2 10 52 53 134 124 +91 3 2 2 10 43 118 134 44 +92 3 2 2 10 118 131 124 134 +93 3 2 2 10 128 108 125 107 +94 3 2 2 10 33 32 125 108 +95 3 2 2 10 104 114 139 103 +96 3 2 2 10 135 112 139 114 +97 3 2 2 10 104 103 140 113 +98 3 2 2 10 136 113 140 111 +99 3 2 2 10 105 115 141 122 +100 3 2 2 10 131 122 141 124 +101 3 2 2 10 101 102 142 128 +102 3 2 2 10 108 128 142 110 +103 3 2 2 10 110 142 139 112 +104 3 2 2 10 102 103 139 142 +105 3 2 2 10 109 111 140 129 +106 3 2 2 10 102 129 140 103 +107 3 2 2 10 51 52 124 141 +108 3 2 2 10 116 126 38 37 +109 3 2 2 10 36 135 116 37 +110 3 2 2 10 12 144 31 2 +111 3 2 2 10 32 31 144 125 +112 3 2 2 10 107 125 144 121 +113 3 2 2 10 13 121 144 12 +114 3 2 2 10 48 109 146 47 +115 3 2 2 10 45 46 143 145 +116 3 2 2 10 47 146 143 46 +117 3 2 2 10 109 129 130 146 +118 3 2 2 10 106 143 146 130 +119 3 2 2 10 143 106 147 145 +120 3 2 2 10 14 15 147 132 +121 3 2 2 10 119 132 147 106 +122 3 2 2 10 16 3 45 145 +123 3 2 2 10 15 16 145 147 +124 3 2 2 10 41 117 127 42 +$EndElements diff --git a/test/test_model/test_non_local_toolbox/parallel_test.msh b/test/test_model/test_non_local_toolbox/parallel_test.msh new file mode 100644 index 000000000..54d9cddc3 --- /dev/null +++ b/test/test_model/test_non_local_toolbox/parallel_test.msh @@ -0,0 +1,2190 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +2 +2 1 "mat_1" +2 2 "mat_2" +$EndPhysicalNames +$Nodes +760 +1 -1 -1 0 +2 -0.3333333333333333 -1 0 +3 1 -1 0 +4 -1 1 0 +5 -0.3333333333333333 1 0 +6 1 1 0 +7 -0.9259259259261259 -1 0 +8 -0.851851851852264 -1 0 +9 -0.7777777777783994 -1 0 +10 -0.7037037037045228 -1 0 +11 -0.6296296296304319 -1 0 +12 -0.5555555555561553 -1 0 +13 -0.4814814814818934 -1 0 +14 -0.4074074074076072 -1 0 +15 -0.2549019607844754 -1 0 +16 -0.1764705882355741 -1 0 +17 -0.09803921568677137 -1 0 +18 -0.0196078431379782 -1 0 +19 0.05882352941081553 -1 0 +20 0.1372549019596017 -1 0 +21 0.2156862745084134 -1 0 +22 0.2941176470571926 -1 0 +23 0.3725490196062002 -1 0 +24 0.450980392155436 -1 0 +25 0.5294117647046463 -1 0 +26 0.6078431372538782 -1 0 +27 0.6862745098030976 -1 0 +28 0.7647058823523272 -1 0 +29 0.8431372549015488 -1 0 +30 0.9215686274507757 -1 0 +31 -0.9259259259261259 1 0 +32 -0.851851851852264 1 0 +33 -0.7777777777783994 1 0 +34 -0.7037037037045228 1 0 +35 -0.6296296296304319 1 0 +36 -0.5555555555561553 1 0 +37 -0.4814814814818934 1 0 +38 -0.4074074074076072 1 0 +39 -1 -0.9200000000002219 0 +40 -1 -0.8400000000004438 0 +41 -1 -0.7600000000006657 0 +42 -1 -0.6800000000008877 0 +43 -1 -0.6000000000011096 0 +44 -1 -0.5200000000013315 0 +45 -1 -0.4400000000015535 0 +46 -1 -0.3600000000017753 0 +47 -1 -0.2800000000019972 0 +48 -1 -0.2000000000022192 0 +49 -1 -0.1200000000024412 0 +50 -1 -0.04000000000266302 0 +51 -1 0.03999999999733728 0 +52 -1 0.1199999999975589 0 +53 -1 0.1999999999977808 0 +54 -1 0.2799999999980027 0 +55 -1 0.3599999999982249 0 +56 -1 0.4399999999984467 0 +57 -1 0.5199999999986684 0 +58 -1 0.5999999999988903 0 +59 -1 0.6799999999991124 0 +60 -1 0.7599999999993341 0 +61 -1 0.839999999999556 0 +62 -1 0.9199999999997781 0 +63 -0.3333333333333333 -0.9200000000002219 0 +64 -0.3333333333333333 -0.8400000000004438 0 +65 -0.3333333333333333 -0.7600000000006657 0 +66 -0.3333333333333333 -0.6800000000008877 0 +67 -0.3333333333333333 -0.6000000000011096 0 +68 -0.3333333333333333 -0.5200000000013315 0 +69 -0.3333333333333333 -0.4400000000015535 0 +70 -0.3333333333333333 -0.3600000000017753 0 +71 -0.3333333333333333 -0.2800000000019972 0 +72 -0.3333333333333333 -0.2000000000022192 0 +73 -0.3333333333333333 -0.1200000000024412 0 +74 -0.3333333333333333 -0.04000000000266302 0 +75 -0.3333333333333333 0.03999999999733728 0 +76 -0.3333333333333333 0.1199999999975589 0 +77 -0.3333333333333333 0.1999999999977808 0 +78 -0.3333333333333333 0.2799999999980027 0 +79 -0.3333333333333333 0.3599999999982249 0 +80 -0.3333333333333333 0.4399999999984467 0 +81 -0.3333333333333333 0.5199999999986684 0 +82 -0.3333333333333333 0.5999999999988903 0 +83 -0.3333333333333333 0.6799999999991124 0 +84 -0.3333333333333333 0.7599999999993341 0 +85 -0.3333333333333333 0.839999999999556 0 +86 -0.3333333333333333 0.9199999999997781 0 +87 -0.2549019607844754 1 0 +88 -0.1764705882355741 1 0 +89 -0.09803921568677137 1 0 +90 -0.0196078431379782 1 0 +91 0.05882352941081553 1 0 +92 0.1372549019596017 1 0 +93 0.2156862745084134 1 0 +94 0.2941176470571926 1 0 +95 0.3725490196062002 1 0 +96 0.450980392155436 1 0 +97 0.5294117647046463 1 0 +98 0.6078431372538782 1 0 +99 0.6862745098030976 1 0 +100 0.7647058823523272 1 0 +101 0.8431372549015488 1 0 +102 0.9215686274507757 1 0 +103 1 -0.9200000000002219 0 +104 1 -0.8400000000004438 0 +105 1 -0.7600000000006657 0 +106 1 -0.6800000000008877 0 +107 1 -0.6000000000011096 0 +108 1 -0.5200000000013315 0 +109 1 -0.4400000000015535 0 +110 1 -0.3600000000017753 0 +111 1 -0.2800000000019972 0 +112 1 -0.2000000000022192 0 +113 1 -0.1200000000024412 0 +114 1 -0.04000000000266302 0 +115 1 0.03999999999733728 0 +116 1 0.1199999999975589 0 +117 1 0.1999999999977808 0 +118 1 0.2799999999980027 0 +119 1 0.3599999999982249 0 +120 1 0.4399999999984467 0 +121 1 0.5199999999986684 0 +122 1 0.5999999999988903 0 +123 1 0.6799999999991124 0 +124 1 0.7599999999993341 0 +125 1 0.839999999999556 0 +126 1 0.9199999999997781 0 +127 -0.6244923549273574 -0.7804476162728123 0 +128 -0.6672821210865347 -0.3981363141022898 0 +129 -0.6546070565370572 -0.1501342028045368 0 +130 -0.6549876531186305 -0.6448073520353281 0 +131 -0.687618036671638 -0.4877235743127334 0 +132 -0.662991527169032 -0.04961904671683437 0 +133 -0.6666459542733651 0.1441432019957372 0 +134 -0.6666615662751374 0.2324109185942875 0 +135 -0.6657143001026753 0.4799321870408348 0 +136 -0.6666651780713242 0.2970878580001537 0 +137 -0.6663753889113118 0.3968954519929966 0 +138 -0.6560175284425774 0.647682552699709 0 +139 -0.6489487102959535 0.8043540454674649 0 +140 -0.4914334971528428 0.8013081036101941 0 +141 -0.4967781346352358 -0.8136867978734854 0 +142 -0.8573417764605045 0.8586666720417473 0 +143 -0.8205201644696922 -0.8750788065476156 0 +144 -0.5001465324794911 0.9371641616555626 0 +145 -0.5166520215486673 -0.9297851450900305 0 +146 -0.9443396432568872 -0.9402472510418199 0 +147 -0.4375568389278687 -0.9374496470532463 0 +148 -0.8501921865700612 0.1540270337199472 0 +149 -0.4999909933375396 0.145439513990369 0 +150 -0.8266989707677244 0.05946672626156468 0 +151 -0.4880258810232836 0.04713591947759244 0 +152 -0.8408324618684195 -0.6533803594796295 0 +153 -0.826405819172509 -0.0443090531025031 0 +154 -0.5137934946953118 -0.04237186312081742 0 +155 -0.8540748231619797 0.6421839792527517 0 +156 -0.4740268662571406 0.6434087470905732 0 +157 -0.8285462133901065 -0.3876825609352906 0 +158 -0.4976824858420978 -0.3824284142856437 0 +159 -0.4880473961795723 -0.1054702152744524 0 +160 -0.8684077064397683 -0.1191761642744301 0 +161 -0.821906478890814 0.5631107390036338 0 +162 -0.4862399563789741 0.5567431347057035 0 +163 -0.8062405654934396 -0.5314484672287578 0 +164 -0.8541361864145768 -0.4583788053768032 0 +165 -0.5015600293332532 -0.4821684630329319 0 +166 -0.8049390915997143 0.335844379477229 0 +167 -0.5280710451144749 0.3355938573168094 0 +168 -0.8331082339413101 0.2599498730172698 0 +169 -0.4992745912700584 0.2560686358079596 0 +170 -0.825099209932868 -0.1869138376003714 0 +171 -0.4724719391519341 -0.170957859863177 0 +172 -0.5205590325227096 -0.2973949323149156 0 +173 -0.8235336074293348 0.4136044564043972 0 +174 -0.5088772633724278 0.4128865809231126 0 +175 -0.475389438600217 -0.6343321934901129 0 +176 -0.7494546432204144 -0.7670885374250602 0 +177 -0.5768505667286512 -0.7442449480650046 0 +178 -0.7698406898983896 0.7439341405826287 0 +179 -0.9219568190305194 0.7764345944748439 0 +180 -0.5457410498033263 -0.8605460963742542 0 +181 -0.5307737233108213 0.8689282965306713 0 +182 -0.6491109705801293 -0.9218559664259203 0 +183 -0.56392009259897 -0.8048398212702833 0 +184 -0.5771920553036334 0.7962643532786153 0 +185 -0.754940055423068 -0.8399272164270225 0 +186 -0.7081717037607804 0.862757252616106 0 +187 -0.7345962277479952 0.9339770509644356 0 +188 -0.9237035150133056 0.8571343600137336 0 +189 -0.928158436571582 -0.7887246819536249 0 +190 -0.6457015386697935 -0.7235512692838604 0 +191 -0.7832505502451312 -0.9265532896430192 0 +192 -0.8748255243959532 -0.9349122021788833 0 +193 -0.9045210102347154 0.9307558922919594 0 +194 -0.4201449982563817 -0.7928640269919773 0 +195 -0.6836801207261622 -0.5677980563037506 0 +196 -0.4697151211356907 -0.8698916569202506 0 +197 -0.4395311549937636 -0.4965542994237602 0 +198 -0.864342469535104 -0.5242966465836461 0 +199 -0.7583061485894145 -0.6156714396482862 0 +200 -0.7605960047827529 -0.4542143824158388 0 +201 -0.5589328210212259 -0.6229263835680147 0 +202 -0.7537505900552766 0.6199889645565002 0 +203 -0.5682270969362844 0.619019684609635 0 +204 -0.8770024795417555 -0.7203102973989448 0 +205 -0.5819090556474992 0.5319079404024698 0 +206 -0.7487847778257903 0.5314943763234234 0 +207 -0.7485303995518826 -0.170961278500834 0 +208 -0.5831751236985908 0.3642509182530955 0 +209 -0.7500871031331759 0.3642797127811306 0 +210 -0.5784625541823176 -0.3481724683805454 0 +211 -0.9227106648752721 -0.1190386604344363 0 +212 -0.9137631510227066 -0.2095564355177125 0 +213 -0.5833485289178013 0.002783626956833984 0 +214 -0.5740021505102716 -0.09218702079842511 0 +215 -0.749221544790817 0.002783626956833984 0 +216 -0.5844821521404916 0.4469284708565369 0 +217 -0.7406816046187994 -0.08706403681024388 0 +218 -0.7473919877286757 0.4470897117150028 0 +219 -0.9141236982689971 0.5693689107456876 0 +220 -0.9119364185580593 -0.05126372956918035 0 +221 -0.4008941191332082 0.02127905204681357 0 +222 -0.9190944810080419 0.07370766894413516 0 +223 -0.4141662935918158 0.09892847880141198 0 +224 -0.7435085903777969 0.09515748908761612 0 +225 -0.58132004753115 0.09773937347300143 0 +226 -0.4380685619207502 -0.04155644135983749 0 +227 -0.7586253749127442 0.1843190229197116 0 +228 -0.5829914569564005 0.188884697971621 0 +229 -0.7484759069081384 0.2787350318359223 0 +230 -0.584805258099573 0.278717038582051 0 +231 -0.4050114461956372 0.1972524722595226 0 +232 -0.9080202880474837 0.2915105616952645 0 +233 -0.4054955743166661 0.3062445215163165 0 +234 -0.8841920956776853 0.4296293537136733 0 +235 -0.3998287469862251 -0.1279614329037643 0 +236 -0.4530003100184419 0.428929577149346 0 +237 -0.3983906762803199 -0.2838061295471579 0 +238 -0.3967145456380078 0.5765956366982687 0 +239 -0.7520861351594814 -0.3776369706956232 0 +240 -0.9241433744849579 -0.3060385988582185 0 +241 -0.4525947653370216 -0.7013524299747442 0 +242 -0.4002133316513193 -0.2177455138215594 0 +243 -0.7186706349198024 0.6894767787917864 0 +244 -0.6328621671115469 0.7277513365320252 0 +245 -0.788552247669306 -0.7114647056032219 0 +246 -0.640637471083455 -0.3019361744588318 0 +247 -0.9160252953912966 -0.6520682434409328 0 +248 -0.4182865221385997 -0.4231902278714372 0 +249 -0.4006128317795927 -0.6477308186442807 0 +250 -0.5032339910315216 -0.76122992622818 0 +251 -0.9158427251984841 -0.3941147599209458 0 +252 -0.7402155092100058 -0.5317651146634402 0 +253 -0.6164011852097693 -0.2207442587790357 0 +254 -0.7157822323799772 -0.7052537161998844 0 +255 -0.5711346785908226 -0.4870792912459441 0 +256 -0.5910540522527449 -0.6847591391684578 0 +257 -0.6256110067176386 -0.8476366178814017 0 +258 -0.7869862404445154 0.8243025699279969 0 +259 -0.5275199191648444 -0.6958593527651393 0 +260 -0.8336502431824969 0.7595939727588925 0 +261 -0.8007386067933593 0.6921994534383267 0 +262 -0.394346282512787 -0.8882586576135511 0 +263 -0.7073965329146505 0.7724298376541272 0 +264 -0.4883930111156681 -0.5578546113514069 0 +265 -0.8491509365191895 -0.5925147606700525 0 +266 -0.6869186018262259 -0.7930672723777387 0 +267 -0.5450020985580005 0.7142479312462844 0 +268 -0.8341686582883933 -0.7966656257487901 0 +269 -0.8616973963562642 0.8059892194369476 0 +270 -0.5874757387560344 -0.9256884119005868 0 +271 -0.7003353186598691 -0.8790597717007178 0 +272 -0.6643393491054927 0.5738206615361978 0 +273 -0.6895948043704794 -0.2370736623094637 0 +274 -0.6664024329624116 0.0498570691527378 0 +275 -0.3933305362977552 0.6876636280830637 0 +276 -0.809861039427745 0.9194902139885692 0 +277 -0.9134495363225035 -0.8721597962527061 0 +278 -0.6730191503732064 0.9375631969675255 0 +279 -0.3811954391029859 -0.9491416609334038 0 +280 -0.8438098276928968 0.4896826996315105 0 +281 -0.4957913148018029 0.4755051382256419 0 +282 -0.5750905929619263 -0.423879999561232 0 +283 -0.6274777878864091 -0.4657669472805289 0 +284 -0.6150719177651186 -0.580511965197597 0 +285 -0.923913343230938 -0.4858356032538904 0 +286 -0.4641773464937841 -0.2511288131657291 0 +287 -0.43996271065373 -0.3318789574445448 0 +288 -0.9442372423009268 -0.7202206445590111 0 +289 -0.5314433475740266 -0.1460922617911571 0 +290 -0.5827727131913574 -0.162026650929698 0 +291 -0.6210796709131001 -0.5206487185401667 0 +292 -0.581230055707008 -0.2738964798825673 0 +293 -0.5384365171215126 -0.2174630366751827 0 +294 -0.8710605370111091 0.7135707072592665 0 +295 -0.7210574327096394 -0.3104457219597467 0 +296 -0.7726201734487623 -0.2456748795498428 0 +297 -0.4083788492509824 0.4847726588703622 0 +298 -0.9472660375206725 0.339395884241571 0 +299 -0.938462949189641 0.4025777539396251 0 +300 -0.3999261187603369 0.3957570379912188 0 +301 -0.3880038524079324 -0.7163894551225112 0 +302 -0.865174559484694 -0.3299145215971327 0 +303 -0.5593620214565314 -0.5418649054893434 0 +304 -0.9341925652500994 0.4731634209628401 0 +305 -0.8883708847554465 0.006508821652336128 0 +306 -0.4075993872337992 -0.5608247691174075 0 +307 -0.8500798112038628 -0.2626458761097465 0 +308 -0.7982607208994243 -0.3190000884745637 0 +309 -0.8784261412971217 0.351759526169291 0 +310 -0.7577726477361018 0.8852541173153972 0 +311 -0.925572007446088 -0.5624525423251605 0 +312 -0.4660153123092644 0.3545954704146153 0 +313 -0.8018249479431654 -0.1216848740576765 0 +314 -0.9439322047205646 0.007076908103463841 0 +315 -0.9373165539246578 0.6773654559614122 0 +316 -0.5870483722123127 0.9341772288764594 0 +317 -0.3864167462065659 -0.488113859283098 0 +318 -0.5981705740708101 0.6766506983909344 0 +319 -0.6223896294171036 0.8669750235806821 0 +320 -0.9301175390112836 0.1548364455419218 0 +321 -0.9202397079283564 0.2233873189950311 0 +322 -0.4648039417830571 0.7340825566702143 0 +323 -0.7947562806570817 0.1232425679972098 0 +324 -0.4033518907016452 0.7833359247375731 0 +325 -0.4300259238408463 0.8700994716250599 0 +326 -0.420460841485607 0.9478772722133815 0 +327 -0.7073013250997473 -0.9545781712949429 0 +328 -0.9576117340402104 0.9626889730729342 0 +329 -0.3736337288899702 0.9669693180532899 0 +330 0.4508308159640792 -0.1802759457247832 0 +331 0.2878816483017712 -0.3715322579997635 0 +332 0.3703604257188499 -0.5494513245142314 0 +333 0.3294345853558869 -0.1615471184526278 0 +334 0.4189291329187566 0.5605265377064119 0 +335 0.4242748751816585 0.3730477779064076 0 +336 0.7541500575037561 0.5453869936773861 0 +337 0.7532989415942151 -0.5965249326275224 0 +338 0.03098737734178242 0.6955217362337818 0 +339 0.0378195376335837 -0.7039765548176496 0 +340 0.6813905836475949 -0.7452788857647963 0 +341 0.8531273246621092 0.8266589451105564 0 +342 0.8562906787517015 -0.8382920433209551 0 +343 -0.2904925795061188 -0.8721173774777647 0 +344 0.07568598954709133 0.5256321229122163 0 +345 0.02175758137025552 0.392647762643465 0 +346 0.6735511377855465 0.1656650061318301 0 +347 -0.01376131212848714 0.02899718288150721 0 +348 0.6989900744058704 0.0714134954488499 0 +349 0.6446606494084912 0.01513793883213999 0 +350 0.6211506387015771 -0.1122676496220926 0 +351 0.01576500406494435 0.1287841027737613 0 +352 -0.05781087807995672 -0.3708690232307246 0 +353 0.6963716693672031 -0.3503402521283111 0 +354 0.5302282347197813 -0.465416077875027 0 +355 0.53492981783488 0.4359841768177635 0 +356 0.546538130090938 0.7053722598910028 0 +357 0.5984225221869495 0.5624646474101394 0 +358 0.3642185206168465 -0.7871003895957696 0 +359 0.5934153903093411 -0.5983798715029891 0 +360 0.5209919521038673 -0.7205263663980557 0 +361 0.207783547776502 0.6556355951596087 0 +362 0.2079512653465247 -0.6976774005296691 0 +363 0.1517673253122465 0.8527899432424759 0 +364 0.1353373331634406 -0.8524698123609364 0 +365 0.578149059606871 0.851795076064813 0 +366 0.5645427434228807 -0.856219176069275 0 +367 -0.1372784201683939 -0.5698195840822946 0 +368 -0.1091710749187856 0.5671664694882281 0 +369 0.8607061817694395 0.4169103172449447 0 +370 -0.02079022021381399 0.8364405012056719 0 +371 0.3787602233843088 -0.4637712616215949 0 +372 0.8444924036180135 -0.4400040766155091 0 +373 -0.0817391651926524 0.8932475748942685 0 +374 -0.03876178214923953 -0.8783897291568521 0 +375 -0.1653618888890701 -0.7222113178046601 0 +376 0.8361804066162064 0.6958323294363311 0 +377 -0.214990889585209 0.7075829412504064 0 +378 0.9321277701825228 0.5652036456385421 0 +379 0.236409848520515 0.4681687202165652 0 +380 0.9321338012134788 -0.8481287707287297 0 +381 -0.2710102704570193 -0.8029980119154044 0 +382 0.9186593491545929 0.8472817195238205 0 +383 -0.2654469864017179 0.8661901384127872 0 +384 0.6769039829666808 0.6894215947030027 0 +385 -0.1476105531898192 0.9305984082665908 0 +386 -0.1279836648971696 -0.9035514617235737 0 +387 0.8018958840324333 -0.9075846862717796 0 +388 0.7163741951469191 -0.6748342071718143 0 +389 0.3221618967486721 0.2613260493188259 0 +390 0.7567366182954574 -0.7520298134259603 0 +391 -0.1439383477594928 -0.8023748862164626 0 +392 -0.1703442858967485 0.3734586589341682 0 +393 0.1647412767900608 -0.2182992406065184 0 +394 -0.1455796773826976 0.2314198350770134 0 +395 -0.1992174952133865 -0.09854268262904642 0 +396 -0.1508805313546217 -0.03418344976830345 0 +397 0.1853176014390969 0.005518235676573058 0 +398 -0.1807763823395043 0.03651385924528738 0 +399 0.1827504435312923 -0.07915147610801621 0 +400 -0.19776065095986 0.09917127454472796 0 +401 0.1821375864442695 0.08655236169136682 0 +402 0.842210524455784 0.07863887597670405 0 +403 0.5459063468899292 0.1559769806073428 0 +404 0.8487851537313837 0.2345914320154336 0 +405 0.8392159015188754 -0.009951450555311325 0 +406 -0.1448598610078251 -0.2590119778596691 0 +407 0.1705107993188411 0.2439371231596141 0 +408 0.1688206237783456 0.3290543124519518 0 +409 0.1852303496643452 -0.3053358999649696 0 +410 0.8134831529354445 -0.1788338136920798 0 +411 -0.0007181255302391443 -0.5361686692124887 0 +412 0.5366693076220141 -0.2966849608815568 0 +413 0.4772291508409621 -0.3329821045812995 0 +414 0.4120889817430798 -0.3911217389966333 0 +415 0.7576330428811404 -0.4636739353420143 0 +416 0.5835434969069777 -0.2243540344058305 0 +417 -0.0924446730855315 0.5015421374591849 0 +418 -0.211726168139856 -0.3930781568774337 0 +419 0.1677292907562871 0.416121237429192 0 +420 0.3934664896499614 0.6782733755740338 0 +421 0.7735907738387717 0.3884044286357831 0 +422 0.2194204769182224 -0.3879969631903369 0 +423 0.3759920278368225 -0.7125404995848921 0 +424 -0.009371290635787288 -0.443245311028042 0 +425 -0.0378176788386923 -0.669446498141252 0 +426 -0.01893394242915192 0.5347763152669012 0 +427 0.3115937177523073 0.6913726047679916 0 +428 0.07868146027075418 -0.7896618590702983 0 +429 0.4683416134262831 0.7417752253964729 0 +430 0.5026572762607875 -0.6034520279648858 0 +431 0.2263493320089005 -0.8223355013842867 0 +432 0.06347877847661404 -0.6301701434879105 0 +433 0.6399941577669275 -0.5252003718289202 0 +434 0.6215661615834747 0.4709047903172094 0 +435 0.2635905934238891 -0.6423734159429799 0 +436 0.23593669378359 0.8400135261091999 0 +437 0.4110828862988562 0.4678333234162706 0 +438 -0.05754925439315456 0.6187531649203677 0 +439 0.7693500901624439 -0.3908270091536976 0 +440 0.3380839464222379 0.6077852743592256 0 +441 0.158623928973225 0.5011116649521032 0 +442 0.286247770798228 -0.7378493704018891 0 +443 0.6075930492916466 -0.3930657659073938 0 +444 0.4642264576750365 -0.6828871913450205 0 +445 0.4742320977032526 0.6452797202154759 0 +446 0.7897224118275503 0.6295803476820427 0 +447 0.4948355507775083 0.8436035553010146 0 +448 0.04060395738875217 -0.8671347953695643 0 +449 0.4494265195333093 -0.5309735115653487 0 +450 0.1566741133920183 -0.7602250248005729 0 +451 0.4835554035529843 -0.8511606607645968 0 +452 0.1261733952568868 -0.675113382028963 0 +453 0.1333704859974818 0.5823229250456847 0 +454 0.7210565691714652 0.4712024239423684 0 +455 0.4517416504426752 -0.7663751366204676 0 +456 0.5526301802339477 0.7781051240864238 0 +457 0.5177942632364068 0.5726028072924982 0 +458 -0.2509091881878571 0.6407363683495451 0 +459 -0.147869827480575 0.65195952297824 0 +460 0.3497718082090116 -0.9266851285349177 0 +461 0.8085417685487142 0.4804397360439072 0 +462 0.8514353969922135 0.5571945284019764 0 +463 0.4668491095113143 0.4231643640192824 0 +464 0.2935590034124374 0.4263035927981709 0 +465 0.7966615425371313 -0.5198006360614196 0 +466 0.626211593008416 0.7967847356252624 0 +467 0.0671821995936232 0.8639019824401164 0 +468 -0.02440388283027889 0.7465511057659346 0 +469 0.0324378999623518 0.6078464607738747 0 +470 0.0118915539623814 0.30293320607986 0 +471 -0.02173325311379598 -0.3169301580218019 0 +472 -0.008856447094295949 -0.7888218387547676 0 +473 0.2394638659917668 0.5684678409461921 0 +474 0.3257409212348304 0.5041887515798973 0 +475 0.6291076785045788 0.2390787296325303 0 +476 0.5452558574735042 -0.7898449406969117 0 +477 0.9259841522451724 -0.7189206621028029 0 +478 0.926532078149646 0.7019809093074048 0 +479 0.6573793168262703 0.8571090023302055 0 +480 0.8398894257413392 -0.5932380411092031 0 +481 0.8696612926816956 -0.5208368818882751 0 +482 0.0005376543057973304 0.9230899073407215 0 +483 0.02826213428542834 0.4749405284165642 0 +484 0.6738118324227549 0.5467238981015818 0 +485 0.5450772132214672 0.5108237319303814 0 +486 0.8800087960850094 0.6270344836874191 0 +487 0.3329898227580617 -0.3094913949599166 0 +488 0.2973324806690067 -0.4287786141303099 0 +489 0.713800603240901 0.6246290673856887 0 +490 0.8782165354295788 -0.6538447919856165 0 +491 0.556942146085684 -0.5343947043227071 0 +492 0.481025151814912 0.496070804500367 0 +493 0.9268110038539028 -0.3967685742109713 0 +494 0.6458197406627291 0.629787563211031 0 +495 0.5544500705003945 -0.6631403599496437 0 +496 0.667860811558479 -0.9176427077388493 0 +497 0.006321130435200273 -0.934662494651444 0 +498 0.6009593390641033 -0.7323471029929389 0 +499 -0.2039455186213591 -0.6417787999482342 0 +500 0.6363544150422114 -0.6709025590467899 0 +501 0.896117925669232 0.3608900093024103 0 +502 0.6929172282837095 -0.2861322189471934 0 +503 0.5460696586691935 0.9187285923202035 0 +504 0.916033549719691 0.4829334586508156 0 +505 0.8771713545215618 0.7632830517725091 0 +506 0.6107484520801518 0.7139659854058462 0 +507 0.9481913412379204 -0.6420833225378739 0 +508 0.5386544949834027 -0.9209622935047785 0 +509 0.7924766063265298 0.8691367977256439 0 +510 0.7278961114349209 -0.8413700148388672 0 +511 0.8938180049662419 -0.7842930860615039 0 +512 -0.0818155887732927 -0.7404056832289673 0 +513 0.7928247730300773 -0.6726427128611996 0 +514 0.5690283905147411 0.6383757306288673 0 +515 -0.155578031266789 0.7521328157456189 0 +516 0.01146919408931085 -0.171954869380737 0 +517 0.9022586514393325 -0.9248579286173996 0 +518 0.8698154134379867 0.9205743185568152 0 +519 -0.2192709294648614 0.9300904632325946 0 +520 -0.0843538401633383 0.7027743007030951 0 +521 0.9236823346260659 -0.5729219905455327 0 +522 0.33102711010049 0.04251673935710332 0 +523 0.7462839295169752 0.695111275657222 0 +524 -0.07927759598138262 -0.8246716183537856 0 +525 0.7822287146882352 0.2334829784056109 0 +526 -0.2402399221718588 -0.246117125821281 0 +527 0.9074341856375356 -0.1600445437608213 0 +528 0.2652466711834908 0.9243862742073377 0 +529 0.2451239911470414 0.2928219893348307 0 +530 0.2528493681468596 -0.2625826784379974 0 +531 -0.07333300847410157 0.3571485347281038 0 +532 0.5562812651861855 0.2337910993247949 0 +533 0.2472114277564539 0.06521096158170891 0 +534 0.4270366577290943 0.03665210550555753 0 +535 0.1074546202563891 -0.1349593876748703 0 +536 -0.07319464965434302 0.27006014190247 0 +537 0.2597530315283658 -0.1158546029118703 0 +538 0.5664840643139766 -0.1519146411938465 0 +539 -0.07614173283605591 0.1751217179009061 0 +540 0.7599815247437782 0.1437126601295968 0 +541 0.4511044416270512 0.2963502800531124 0 +542 0.08905620785417412 0.1873977523253636 0 +543 -0.2070493182332927 0.2293781653998803 0 +544 -0.2558455609091826 0.4047470643980537 0 +545 0.09149997717323338 0.2752205232212785 0 +546 -0.2013333598282817 0.4420304039911265 0 +547 0.4757066065599606 0.9325573332251427 0 +548 0.4047037902405795 -0.3364921156462276 0 +549 0.1040891915008211 -0.2736966173692181 0 +550 0.5130684941947552 -0.02303776035267446 0 +551 0.6058877923619497 0.09544767248009522 0 +552 -0.07214650886340274 -0.2010853413913382 0 +553 0.1047516668609316 0.1106677242203482 0 +554 0.7630497499140045 -0.03803509871278832 0 +555 0.2513225328645418 -0.188719375175992 0 +556 -0.2553171017070138 0.1535699053822728 0 +557 -0.2446113091230612 -0.02266132661312603 0 +558 0.9225327696153702 0.13756162703217 0 +559 -0.2602785039071151 -0.1542957905136983 0 +560 0.9160997127447637 -0.07056810288203419 0 +561 0.9108273364916 -0.3197783138694478 0 +562 0.930248641194132 0.03520869252654513 0 +563 -0.2627702384129518 0.05639593400821652 0 +564 0.2511274160680965 0.1389993060418055 0 +565 -0.1347412710768505 -0.3775521932660622 0 +566 0.4650970165074158 -0.9427956125538957 0 +567 -0.1823953098350677 -0.3153518510285358 0 +568 0.1836586398955459 -0.535268012270296 0 +569 0.09214599593487049 0.3615414893226916 0 +570 -0.119344879253717 -0.1144786067912538 0 +571 0.8761239560901262 -0.3802623382262479 0 +572 -0.2642572295746519 -0.3341645583967067 0 +573 -0.1012125164843963 0.03391634527348319 0 +574 0.4247126365573582 -0.04704972233871929 0 +575 0.07379828852035447 -0.2071705236335691 0 +576 0.265175404243797 -0.02895856055056512 0 +577 0.7714187848421503 0.04170454602971785 0 +578 0.8766958354816772 0.2963161654444493 0 +579 0.30608645206572 0.8587012394102804 0 +580 0.318992529289046 0.173643628765207 0 +581 0.2392071563637252 0.3791386041434144 0 +582 0.7606838436750247 -0.2994772417005772 0 +583 0.4165445849817408 0.8863172520766271 0 +584 0.2492759659819412 0.2162299268561925 0 +585 0.307789665728289 0.3526774884042601 0 +586 0.07521680162229366 0.9343778624537897 0 +587 0.3945350088258401 -0.195418482274059 0 +588 0.06577796515527295 0.002061325616971255 0 +589 -0.2587282984945163 -0.5086317994655229 0 +590 0.9190106175965136 0.2337614530077867 0 +591 0.8413007250889537 -0.2633372097968917 0 +592 0.006072226073742693 -0.2549815364305744 0 +593 0.28483244299162 -0.9003388629288847 0 +594 -0.1698935275235141 -0.4744532017183704 0 +595 0.09770278185983461 -0.9264659783821004 0 +596 0.7996936560594574 0.3021537879297467 0 +597 0.1893272574902737 0.9181186087451305 0 +598 0.3084567318579005 0.1005372544136531 0 +599 0.1139420809863027 -0.3634724479179611 0 +600 0.338824399579243 -0.08363354439324056 0 +601 0.3555754675059907 -0.01731196009002556 0 +602 0.750024466588689 -0.1796415944800979 0 +603 0.4086561422274546 -0.9020501042103343 0 +604 0.02214288507568957 -0.0700508277249956 0 +605 0.02644283428823457 -0.3751906637556569 0 +606 0.1478822671388655 -0.4601468960804789 0 +607 0.1915927523553709 -0.6142566007187205 0 +608 -0.1242891827704753 0.4445122517178897 0 +609 -0.2675694981276602 0.566335335822816 0 +610 0.06875727798578252 -0.4920581224287041 0 +611 0.5132223143333541 -0.2001887869340697 0 +612 -0.04971214242790117 0.9540843705587476 0 +613 0.8280836510050344 -0.09535163853142326 0 +614 0.8413183196945435 0.1686744748773354 0 +615 0.1245786207942827 0.9111581991840416 0 +616 0.6310478850831078 0.923299601879914 0 +617 0.5059123110019579 0.3552141602613095 0 +618 0.3044990386402959 -0.8260763643308568 0 +619 -0.1646967458767389 -0.1791736475293985 0 +620 0.3642908092705765 0.8324201325494256 0 +621 0.0907008201445263 0.4453324676127053 0 +622 0.8413608745637156 0.3529349417114669 0 +623 0.2387267075001884 -0.4837965354275237 0 +624 -0.2161905009585778 -0.8621576596462995 0 +625 0.3172797697304954 -0.5975621229303623 0 +626 0.2518724215665587 -0.5621023225878843 0 +627 0.1934256582239459 -0.9231424655819773 0 +628 0.8315329806587433 -0.3500486663134575 0 +629 -0.1492655054969645 0.2999240650707995 0 +630 0.9446737760203183 0.7796857186207611 0 +631 0.4105584660622567 0.9519884332625339 0 +632 0.5317741214150502 -0.3770758840234375 0 +633 -0.08711095557656426 -0.3016611633303758 0 +634 0.6469666806251693 -0.2437185297799305 0 +635 0.351698713777412 -0.3815763105204479 0 +636 -0.09353826188362868 0.7987776180102182 0 +637 0.3351072666724287 -0.2308413464122389 0 +638 0.6081950179678499 -0.9017968114393392 0 +639 0.6154466089539621 -0.4644825438377278 0 +640 0.6834750130593659 -0.4428613333329899 0 +641 0.7304882172282487 -0.9338325484510682 0 +642 0.4002671823196738 -0.6211235780061323 0 +643 -0.05591773851246462 -0.9454857637614669 0 +644 0.4063905961757812 -0.1258203219999712 0 +645 0.6788473561438677 0.3878477284515522 0 +646 -0.2528886578608556 -0.7218628754625882 0 +647 0.04576261594706105 -0.3168542846990425 0 +648 -0.2458912159522055 0.4946955815070218 0 +649 -0.2772614385754695 -0.3950961042799813 0 +650 0.4634859539315725 -0.4280262282210496 0 +651 0.5683820255349146 0.3010442515328657 0 +652 0.774212602884089 0.7781360154209722 0 +653 0.7284767924832001 0.3123880418104026 0 +654 0.3798554962334621 0.7510808973838479 0 +655 -0.170236761965572 0.8506913009566408 0 +656 0.5893308014889409 0.3778375317972154 0 +657 0.4308163158917767 -0.2646720068400692 0 +658 0.1276283996643481 -0.5905558730725458 0 +659 0.3543968951489299 -0.8623591743238406 0 +660 -0.04316351518392941 0.4509279217053515 0 +661 0.04004852444628759 0.7798462270872752 0 +662 0.691585034197439 0.8022558349380251 0 +663 0.424773610937914 0.8110394125414779 0 +664 0.4885220023819107 -0.1157008831437231 0 +665 0.7164448779648906 0.9206044172492969 0 +666 0.3582031786896948 0.4067827272565083 0 +667 -0.1559443367340285 0.5040862407589783 0 +668 -0.1139332792967346 -0.6537482851763414 0 +669 0.4041230517403432 0.6241700625197997 0 +670 0.9437422446526196 0.3191864716893345 0 +671 0.8417943759747502 -0.750705083762723 0 +672 0.2543859354458 -0.3269267988982385 0 +673 0.310346947217595 0.7847699967459132 0 +674 0.9477337288834358 0.6348438077262739 0 +675 0.4896671793824416 0.2201160329445528 0 +676 0.3090553380949012 -0.514243696868651 0 +677 -0.1730952050079148 0.1654583066256123 0 +678 0.1729458184664439 0.1627160552678173 0 +679 0.007775127692827233 -0.614222297780314 0 +680 0.009394372300446763 0.2210382842084775 0 +681 0.3252644381648781 -0.6632510570175412 0 +682 0.412513722397778 -0.8338090931030018 0 +683 0.3790424500011799 0.3150766834285765 0 +684 0.9298177472919271 -0.4804508962953197 0 +685 -0.2141616373145244 -0.9423520039625769 0 +686 0.5205634572783044 0.07200051002568553 0 +687 0.6199286377401492 -0.3057965612463592 0 +688 -0.07510483034684096 -0.5060404321857541 0 +689 0.3470562357467395 0.9219733330723148 0 +690 0.9360999836351638 0.3966533761473627 0 +691 0.2380221886741546 0.7467408047891848 0 +692 -0.2103101197948715 -0.5590829704898292 0 +693 -0.05750675223929047 -0.5868135365579834 0 +694 0.9482307735414779 -0.7873082367159403 0 +695 0.7477256615419348 -0.1143663188520017 0 +696 0.06019740425305958 0.06033215768713918 0 +697 -0.06610157490812452 -0.04879416668706626 0 +698 0.7989544178449626 0.940942767537797 0 +699 -0.1306605032235158 0.1033694561250789 0 +700 0.6861875036940401 -0.1438106957750942 0 +701 0.9209041025695848 -0.2390507955767557 0 +702 0.2751517315667942 0.6334823699390395 0 +703 0.19320438099413 -0.1473968164954534 0 +704 0.07063610879826704 -0.4297092676054033 0 +705 -0.2754492783661755 0.728525394403077 0 +706 0.121254656740209 0.03700902749744817 0 +707 -0.2700774367997275 -0.6074355218561081 0 +708 0.1131877223714935 -0.04061352608840541 0 +709 0.247015505695293 -0.9558703321277155 0 +710 0.6106830230672757 0.1801351708570647 0 +711 -0.04479617677204878 -0.1212727623950782 0 +712 0.7948267626616252 -0.8190615823358236 0 +713 0.5843314223963174 0.0219897947247496 0 +714 0.6876575991089584 0.7459459069583885 0 +715 0.7264196876398439 0.8454484135328286 0 +716 0.6397439323089948 -0.1835993699335191 0 +717 -0.2276982278803913 0.7854556016180672 0 +718 0.7078183763228549 -0.2251491189147913 0 +719 0.6849682004601036 -0.06264916950773469 0 +720 -0.08760198367061081 -0.4331826712576287 0 +721 0.6280143520813333 -0.8263570913629968 0 +722 -0.2458268956321301 0.307916455239764 0 +723 0.110461412165661 0.6638888232746314 0 +724 0.573991279017215 -0.3431557930146869 0 +725 0.3983438713541476 0.2147522261103778 0 +726 -0.2818256209576052 0.9397161478808786 0 +727 -0.2735024776181197 -0.9295531143810005 0 +728 0.7069088706606104 0.005056903740016994 0 +729 -0.2944509896935912 0.003128339952431336 0 +730 0.09125735825609399 0.7326487438364229 0 +731 -0.2098779331850031 -0.782320950209083 0 +732 0.1551165664146321 0.7309359671483333 0 +733 0.650716295248303 0.3107675878769496 0 +734 0.5142694445465101 0.2813031648233271 0 +735 0.1784366727252177 0.793573142291677 0 +736 0.1139681077913502 0.7922826676743835 0 +737 0.6757385414276664 -0.5950613151606716 0 +738 -0.1962258569001853 0.5708299198174716 0 +739 0.4594357477702311 0.1338939455053811 0 +740 -0.2650612366538189 -0.6627692993169545 0 +741 0.8707805415578798 -0.2103165907066372 0 +742 -0.06120221212150218 0.09403776099094729 0 +743 -0.02057634001652747 0.6742893536794106 0 +744 0.7178002065444076 -0.523853754058923 0 +745 0.06716406662409696 -0.5642123981204208 0 +746 -0.2741547949820459 -0.08709995995219511 0 +747 0.5988540833825524 -0.04040764156460153 0 +748 0.7746621129221933 -0.2292877957168875 0 +749 0.3738821080168181 0.1169993166095467 0 +750 0.7040103572422738 0.2341825006644866 0 +751 0.1190181302617279 -0.528448260394489 0 +752 0.1001090573499544 -0.7328768834007398 0 +753 -0.2870522318629903 0.7960342268865646 0 +754 -0.2501885532133379 -0.4422518524685723 0 +755 0.2193056203864178 -0.7545218242791044 0 +756 -0.0226675442681743 -0.7256626437356591 0 +757 -0.2749719964478207 0.2341729052035402 0 +758 0.5576158565949545 -0.08866571517538768 0 +759 0.9516738983405593 0.921309339679995 0 +760 0.955956819722527 -0.9612144821544054 0 +$EndNodes +$Elements +1416 +1 2 2 1 6 144 37 36 +2 2 2 1 6 13 145 12 +3 2 2 1 6 127 183 177 +4 2 2 1 6 141 183 180 +5 2 2 1 6 184 140 181 +6 2 2 1 6 187 34 33 +7 2 2 1 6 190 127 177 +8 2 2 1 6 9 191 8 +9 2 2 1 6 142 193 188 +10 2 2 1 6 196 141 180 +11 2 2 1 6 145 196 180 +12 2 2 1 6 188 62 61 +13 2 2 1 6 31 193 32 +14 2 2 1 6 191 192 8 +15 2 2 1 6 192 7 8 +16 2 2 1 6 192 146 7 +17 2 2 1 6 191 143 192 +18 2 2 1 6 191 185 143 +19 2 2 1 6 194 141 196 +20 2 2 1 6 147 196 145 +21 2 2 1 6 65 194 64 +22 2 2 1 6 189 41 40 +23 2 2 1 6 147 13 14 +24 2 2 1 6 145 13 147 +25 2 2 1 6 146 1 7 +26 2 2 1 6 39 1 146 +27 2 2 1 6 198 163 164 +28 2 2 1 6 200 164 163 +29 2 2 1 6 205 162 203 +30 2 2 1 6 161 206 202 +31 2 2 1 6 152 245 199 +32 2 2 1 6 245 152 204 +33 2 2 1 6 250 194 241 +34 2 2 1 6 194 250 141 +35 2 2 1 6 130 254 190 +36 2 2 1 6 254 130 199 +37 2 2 1 6 256 130 190 +38 2 2 1 6 177 256 190 +39 2 2 1 6 130 256 201 +40 2 2 1 6 259 175 201 +41 2 2 1 6 175 259 241 +42 2 2 1 6 260 178 258 +43 2 2 1 6 261 178 260 +44 2 2 1 6 262 64 194 +45 2 2 1 6 196 262 194 +46 2 2 1 6 263 139 186 +47 2 2 1 6 175 264 201 +48 2 2 1 6 265 163 198 +49 2 2 1 6 266 127 190 +50 2 2 1 6 268 143 185 +51 2 2 1 6 176 268 185 +52 2 2 1 6 269 142 188 +53 2 2 1 6 179 269 188 +54 2 2 1 6 142 269 258 +55 2 2 1 6 182 270 257 +56 2 2 1 6 270 180 257 +57 2 2 1 6 271 182 257 +58 2 2 1 6 138 272 203 +59 2 2 1 6 272 138 202 +60 2 2 1 6 273 129 207 +61 2 2 1 6 277 189 40 +62 2 2 1 6 34 278 35 +63 2 2 1 6 279 14 2 +64 2 2 1 6 63 279 2 +65 2 2 1 6 14 279 147 +66 2 2 1 6 161 280 206 +67 2 2 1 6 281 162 205 +68 2 2 1 6 250 183 141 +69 2 2 1 6 177 183 250 +70 2 2 1 6 257 183 127 +71 2 2 1 6 180 183 257 +72 2 2 1 6 258 276 142 +73 2 2 1 6 263 258 178 +74 2 2 1 6 186 258 263 +75 2 2 1 6 266 254 176 +76 2 2 1 6 190 254 266 +77 2 2 1 6 243 263 178 +78 2 2 1 6 39 277 40 +79 2 2 1 6 39 146 277 +80 2 2 1 6 261 243 178 +81 2 2 1 6 254 245 176 +82 2 2 1 6 199 245 254 +83 2 2 1 6 259 256 177 +84 2 2 1 6 201 256 259 +85 2 2 1 6 272 206 135 +86 2 2 1 6 202 206 272 +87 2 2 1 6 205 272 135 +88 2 2 1 6 205 203 272 +89 2 2 1 6 219 280 161 +90 2 2 1 6 250 259 177 +91 2 2 1 6 250 241 259 +92 2 2 1 6 260 269 179 +93 2 2 1 6 260 258 269 +94 2 2 1 6 185 266 176 +95 2 2 1 6 135 216 205 +96 2 2 1 6 281 216 174 +97 2 2 1 6 205 216 281 +98 2 2 1 6 218 135 206 +99 2 2 1 6 218 280 173 +100 2 2 1 6 218 206 280 +101 2 2 1 6 167 208 230 +102 2 2 1 6 209 166 229 +103 2 2 1 6 137 208 216 +104 2 2 1 6 209 137 218 +105 2 2 1 6 222 52 51 +106 2 2 1 6 222 150 148 +107 2 2 1 6 76 223 75 +108 2 2 1 6 151 223 149 +109 2 2 1 6 151 221 223 +110 2 2 1 6 221 75 223 +111 2 2 1 6 224 274 133 +112 2 2 1 6 274 225 133 +113 2 2 1 6 225 151 149 +114 2 2 1 6 277 192 143 +115 2 2 1 6 192 277 146 +116 2 2 1 6 64 262 63 +117 2 2 1 6 147 262 196 +118 2 2 1 6 262 147 279 +119 2 2 1 6 262 279 63 +120 2 2 1 6 207 129 217 +121 2 2 1 6 200 131 128 +122 2 2 1 6 200 157 164 +123 2 2 1 6 239 157 200 +124 2 2 1 6 128 239 200 +125 2 2 1 6 73 235 72 +126 2 2 1 6 171 235 159 +127 2 2 1 6 171 242 235 +128 2 2 1 6 242 72 235 +129 2 2 1 6 220 160 153 +130 2 2 1 6 211 160 220 +131 2 2 1 6 159 226 154 +132 2 2 1 6 159 235 226 +133 2 2 1 6 215 153 217 +134 2 2 1 6 132 215 217 +135 2 2 1 6 154 214 159 +136 2 2 1 6 154 213 214 +137 2 2 1 6 213 132 214 +138 2 2 1 6 193 62 188 +139 2 2 1 6 265 152 199 +140 2 2 1 6 195 199 130 +141 2 2 1 6 195 252 199 +142 2 2 1 6 252 163 199 +143 2 2 1 6 163 265 199 +144 2 2 1 6 154 226 151 +145 2 2 1 6 221 151 226 +146 2 2 1 6 169 231 233 +147 2 2 1 6 231 76 77 +148 2 2 1 6 223 76 231 +149 2 2 1 6 231 169 149 +150 2 2 1 6 149 223 231 +151 2 2 1 6 212 170 160 +152 2 2 1 6 160 211 212 +153 2 2 1 6 237 70 71 +154 2 2 1 6 248 165 197 +155 2 2 1 6 70 248 69 +156 2 2 1 6 248 158 165 +157 2 2 1 6 281 174 236 +158 2 2 1 6 173 280 234 +159 2 2 1 6 251 46 45 +160 2 2 1 6 157 251 164 +161 2 2 1 6 82 238 81 +162 2 2 1 6 162 238 156 +163 2 2 1 6 219 58 57 +164 2 2 1 6 219 161 155 +165 2 2 1 6 249 66 67 +166 2 2 1 6 249 175 241 +167 2 2 1 6 42 247 43 +168 2 2 1 6 152 247 204 +169 2 2 1 6 265 247 152 +170 2 2 1 6 274 132 213 +171 2 2 1 6 151 213 154 +172 2 2 1 6 151 225 213 +173 2 2 1 6 213 225 274 +174 2 2 1 6 132 274 215 +175 2 2 1 6 215 150 153 +176 2 2 1 6 224 150 215 +177 2 2 1 6 224 215 274 +178 2 2 1 6 246 128 210 +179 2 2 1 6 172 210 158 +180 2 2 1 6 134 230 136 +181 2 2 1 6 134 228 230 +182 2 2 1 6 228 169 230 +183 2 2 1 6 229 134 136 +184 2 2 1 6 227 134 229 +185 2 2 1 6 168 227 229 +186 2 2 1 6 187 278 34 +187 2 2 1 6 134 227 133 +188 2 2 1 6 148 227 168 +189 2 2 1 6 224 133 227 +190 2 2 1 6 228 134 133 +191 2 2 1 6 228 149 169 +192 2 2 1 6 225 149 228 +193 2 2 1 6 133 225 228 +194 2 2 1 6 253 129 273 +195 2 2 1 6 191 271 185 +196 2 2 1 6 187 33 276 +197 2 2 1 6 276 193 142 +198 2 2 1 6 193 276 32 +199 2 2 1 6 33 32 276 +200 2 2 1 6 275 82 83 +201 2 2 1 6 275 156 238 +202 2 2 1 6 82 275 238 +203 2 2 1 6 184 267 140 +204 2 2 1 6 246 253 273 +205 2 2 1 6 156 203 162 +206 2 2 1 6 156 267 203 +207 2 2 1 6 131 252 195 +208 2 2 1 6 252 131 200 +209 2 2 1 6 163 252 200 +210 2 2 1 6 127 266 257 +211 2 2 1 6 271 266 185 +212 2 2 1 6 257 266 271 +213 2 2 1 6 138 243 202 +214 2 2 1 6 202 155 161 +215 2 2 1 6 261 155 202 +216 2 2 1 6 202 243 261 +217 2 2 1 6 245 268 176 +218 2 2 1 6 189 268 204 +219 2 2 1 6 268 189 277 +220 2 2 1 6 268 277 143 +221 2 2 1 6 204 268 245 +222 2 2 1 6 136 208 137 +223 2 2 1 6 136 230 208 +224 2 2 1 6 209 136 137 +225 2 2 1 6 229 136 209 +226 2 2 1 6 174 208 167 +227 2 2 1 6 174 216 208 +228 2 2 1 6 209 173 166 +229 2 2 1 6 218 173 209 +230 2 2 1 6 211 50 49 +231 2 2 1 6 220 50 211 +232 2 2 1 6 48 211 49 +233 2 2 1 6 48 212 211 +234 2 2 1 6 242 71 72 +235 2 2 1 6 237 71 242 +236 2 2 1 6 46 240 47 +237 2 2 1 6 46 251 240 +238 2 2 1 6 158 282 165 +239 2 2 1 6 283 128 131 +240 2 2 1 6 284 195 130 +241 2 2 1 6 201 284 130 +242 2 2 1 6 285 198 164 +243 2 2 1 6 251 285 164 +244 2 2 1 6 242 286 237 +245 2 2 1 6 286 242 171 +246 2 2 1 6 158 287 172 +247 2 2 1 6 288 41 189 +248 2 2 1 6 204 288 189 +249 2 2 1 6 289 171 159 +250 2 2 1 6 214 289 159 +251 2 2 1 6 290 214 129 +252 2 2 1 6 253 290 129 +253 2 2 1 6 214 290 289 +254 2 2 1 6 195 291 131 +255 2 2 1 6 291 195 284 +256 2 2 1 6 292 210 172 +257 2 2 1 6 292 253 246 +258 2 2 1 6 210 292 246 +259 2 2 1 6 293 171 289 +260 2 2 1 6 179 294 260 +261 2 2 1 6 128 295 239 +262 2 2 1 6 295 128 246 +263 2 2 1 6 170 296 207 +264 2 2 1 6 81 297 80 +265 2 2 1 6 298 55 54 +266 2 2 1 6 299 56 55 +267 2 2 1 6 300 79 80 +268 2 2 1 6 301 66 249 +269 2 2 1 6 241 301 249 +270 2 2 1 6 251 302 240 +271 2 2 1 6 302 251 157 +272 2 2 1 6 304 57 56 +273 2 2 1 6 150 305 153 +274 2 2 1 6 305 220 153 +275 2 2 1 6 306 197 264 +276 2 2 1 6 170 307 296 +277 2 2 1 6 173 309 166 +278 2 2 1 6 309 173 234 +279 2 2 1 6 310 186 187 +280 2 2 1 6 310 276 258 +281 2 2 1 6 276 310 187 +282 2 2 1 6 186 310 258 +283 2 2 1 6 198 311 265 +284 2 2 1 6 311 247 265 +285 2 2 1 6 312 174 167 +286 2 2 1 6 174 312 236 +287 2 2 1 6 160 313 153 +288 2 2 1 6 313 217 153 +289 2 2 1 6 293 286 171 +290 2 2 1 6 172 286 293 +291 2 2 1 6 298 299 55 +292 2 2 1 6 299 304 56 +293 2 2 1 6 299 234 304 +294 2 2 1 6 297 300 80 +295 2 2 1 6 297 236 300 +296 2 2 1 6 287 286 172 +297 2 2 1 6 237 286 287 +298 2 2 1 6 291 283 131 +299 2 2 1 6 255 283 291 +300 2 2 1 6 261 294 155 +301 2 2 1 6 261 260 294 +302 2 2 1 6 239 308 157 +303 2 2 1 6 306 175 249 +304 2 2 1 6 264 175 306 +305 2 2 1 6 296 273 207 +306 2 2 1 6 293 292 172 +307 2 2 1 6 253 292 293 +308 2 2 1 6 293 290 253 +309 2 2 1 6 289 290 293 +310 2 2 1 6 296 307 308 +311 2 2 1 6 306 67 68 +312 2 2 1 6 67 306 249 +313 2 2 1 6 43 311 44 +314 2 2 1 6 311 43 247 +315 2 2 1 6 65 301 194 +316 2 2 1 6 301 65 66 +317 2 2 1 6 301 241 194 +318 2 2 1 6 288 42 41 +319 2 2 1 6 42 288 247 +320 2 2 1 6 288 204 247 +321 2 2 1 6 165 264 197 +322 2 2 1 6 255 303 165 +323 2 2 1 6 255 165 282 +324 2 2 1 6 303 264 165 +325 2 2 1 6 278 187 186 +326 2 2 1 6 217 129 132 +327 2 2 1 6 129 214 132 +328 2 2 1 6 303 201 264 +329 2 2 1 6 201 303 284 +330 2 2 1 6 291 303 255 +331 2 2 1 6 284 303 291 +332 2 2 1 6 285 45 44 +333 2 2 1 6 45 285 251 +334 2 2 1 6 198 285 311 +335 2 2 1 6 311 285 44 +336 2 2 1 6 229 166 168 +337 2 2 1 6 167 230 169 +338 2 2 1 6 170 313 160 +339 2 2 1 6 313 170 207 +340 2 2 1 6 217 313 207 +341 2 2 1 6 12 270 11 +342 2 2 1 6 145 270 12 +343 2 2 1 6 270 182 11 +344 2 2 1 6 270 145 180 +345 2 2 1 6 137 216 135 +346 2 2 1 6 218 137 135 +347 2 2 1 6 282 210 128 +348 2 2 1 6 210 282 158 +349 2 2 1 6 283 255 282 +350 2 2 1 6 128 283 282 +351 2 2 1 6 184 139 244 +352 2 2 1 6 184 244 267 +353 2 2 1 6 236 297 281 +354 2 2 1 6 238 297 81 +355 2 2 1 6 162 297 238 +356 2 2 1 6 162 281 297 +357 2 2 1 6 237 287 70 +358 2 2 1 6 248 287 158 +359 2 2 1 6 287 248 70 +360 2 2 1 6 304 219 57 +361 2 2 1 6 219 304 280 +362 2 2 1 6 304 234 280 +363 2 2 1 6 243 138 244 +364 2 2 1 6 139 263 244 +365 2 2 1 6 243 244 263 +366 2 2 1 6 60 179 61 +367 2 2 1 6 188 61 179 +368 2 2 1 6 305 150 222 +369 2 2 1 6 307 212 240 +370 2 2 1 6 212 307 170 +371 2 2 1 6 314 51 50 +372 2 2 1 6 314 220 305 +373 2 2 1 6 220 314 50 +374 2 2 1 6 316 35 278 +375 2 2 1 6 317 69 248 +376 2 2 1 6 197 317 248 +377 2 2 1 6 69 317 68 +378 2 2 1 6 203 318 138 +379 2 2 1 6 244 318 267 +380 2 2 1 6 318 244 138 +381 2 2 1 6 318 203 267 +382 2 2 1 6 186 319 278 +383 2 2 1 6 316 278 319 +384 2 2 1 6 314 222 51 +385 2 2 1 6 305 222 314 +386 2 2 1 6 317 306 68 +387 2 2 1 6 197 306 317 +388 2 2 1 6 316 36 35 +389 2 2 1 6 36 316 144 +390 2 2 1 6 308 302 157 +391 2 2 1 6 302 307 240 +392 2 2 1 6 308 307 302 +393 2 2 1 6 60 315 179 +394 2 2 1 6 315 60 59 +395 2 2 1 6 315 294 179 +396 2 2 1 6 58 315 59 +397 2 2 1 6 155 315 219 +398 2 2 1 6 155 294 315 +399 2 2 1 6 315 58 219 +400 2 2 1 6 139 319 186 +401 2 2 1 6 184 319 139 +402 2 2 1 6 319 184 181 +403 2 2 1 6 312 167 169 +404 2 2 1 6 233 312 169 +405 2 2 1 6 166 309 168 +406 2 2 1 6 309 232 168 +407 2 2 1 6 77 78 231 +408 2 2 1 6 78 233 231 +409 2 2 1 6 54 232 298 +410 2 2 1 6 312 233 300 +411 2 2 1 6 312 300 236 +412 2 2 1 6 239 295 308 +413 2 2 1 6 273 295 246 +414 2 2 1 6 295 273 296 +415 2 2 1 6 308 295 296 +416 2 2 1 6 298 232 309 +417 2 2 1 6 299 309 234 +418 2 2 1 6 298 309 299 +419 2 2 1 6 222 320 52 +420 2 2 1 6 320 222 148 +421 2 2 1 6 321 168 232 +422 2 2 1 6 168 321 148 +423 2 2 1 6 267 322 140 +424 2 2 1 6 322 267 156 +425 2 2 1 6 320 53 52 +426 2 2 1 6 233 78 79 +427 2 2 1 6 233 79 300 +428 2 2 1 6 144 316 181 +429 2 2 1 6 316 319 181 +430 2 2 1 6 73 74 235 +431 2 2 1 6 74 226 235 +432 2 2 1 6 74 75 221 +433 2 2 1 6 226 74 221 +434 2 2 1 6 212 47 240 +435 2 2 1 6 47 212 48 +436 2 2 1 6 323 148 150 +437 2 2 1 6 323 224 227 +438 2 2 1 6 224 323 150 +439 2 2 1 6 148 323 227 +440 2 2 1 6 54 53 321 +441 2 2 1 6 321 53 320 +442 2 2 1 6 232 54 321 +443 2 2 1 6 321 320 148 +444 2 2 1 6 325 324 85 +445 2 2 1 6 86 325 85 +446 2 2 1 6 275 83 84 +447 2 2 1 6 275 322 156 +448 2 2 1 6 84 85 324 +449 2 2 1 6 84 324 275 +450 2 2 1 6 322 324 140 +451 2 2 1 6 322 275 324 +452 2 2 1 6 140 325 181 +453 2 2 1 6 325 144 181 +454 2 2 1 6 140 324 325 +455 2 2 1 6 325 326 144 +456 2 2 1 6 326 325 86 +457 2 2 1 6 271 327 182 +458 2 2 1 6 327 271 191 +459 2 2 1 6 31 328 193 +460 2 2 1 6 62 328 4 +461 2 2 1 6 328 62 193 +462 2 2 1 6 328 31 4 +463 2 2 1 6 38 329 5 +464 2 2 1 6 86 329 326 +465 2 2 1 6 329 86 5 +466 2 2 1 6 329 38 326 +467 2 2 1 6 327 9 10 +468 2 2 1 6 191 9 327 +469 2 2 1 6 11 327 10 +470 2 2 1 6 11 182 327 +471 2 2 1 6 38 37 326 +472 2 2 1 6 37 144 326 +473 2 2 2 10 343 64 63 +474 2 2 2 10 381 64 343 +475 2 2 2 10 385 89 88 +476 2 2 2 10 17 386 16 +477 2 2 2 10 387 28 29 +478 2 2 2 10 378 121 122 +479 2 2 2 10 381 65 64 +480 2 2 2 10 426 368 417 +481 2 2 2 10 438 368 426 +482 2 2 2 10 372 439 415 +483 2 2 2 10 379 441 419 +484 2 2 2 10 442 358 423 +485 2 2 2 10 448 364 428 +486 2 2 2 10 450 364 431 +487 2 2 2 10 364 450 428 +488 2 2 2 10 339 452 432 +489 2 2 2 10 453 344 441 +490 2 2 2 10 358 455 423 +491 2 2 2 10 356 456 429 +492 2 2 2 10 334 457 445 +493 2 2 2 10 82 458 83 +494 2 2 2 10 459 377 458 +495 2 2 2 10 369 461 421 +496 2 2 2 10 336 462 446 +497 2 2 2 10 462 336 461 +498 2 2 2 10 335 463 437 +499 2 2 2 10 465 372 415 +500 2 2 2 10 466 365 456 +501 2 2 2 10 344 469 426 +502 2 2 2 10 339 472 428 +503 2 2 2 10 379 473 441 +504 2 2 2 10 334 474 437 +505 2 2 2 10 474 334 440 +506 2 2 2 10 366 476 451 +507 2 2 2 10 479 365 466 +508 2 2 2 10 337 480 465 +509 2 2 2 10 481 372 465 +510 2 2 2 10 370 482 373 +511 2 2 2 10 484 357 434 +512 2 2 2 10 485 355 434 +513 2 2 2 10 485 357 457 +514 2 2 2 10 357 485 434 +515 2 2 2 10 486 376 446 +516 2 2 2 10 376 486 478 +517 2 2 2 10 488 331 422 +518 2 2 2 10 489 336 446 +519 2 2 2 10 336 489 484 +520 2 2 2 10 491 359 433 +521 2 2 2 10 359 491 430 +522 2 2 2 10 492 334 437 +523 2 2 2 10 334 492 457 +524 2 2 2 10 494 357 484 +525 2 2 2 10 495 359 430 +526 2 2 2 10 360 498 495 +527 2 2 2 10 500 359 495 +528 2 2 2 10 121 504 120 +529 2 2 2 10 505 376 478 +530 2 2 2 10 356 506 456 +531 2 2 2 10 507 106 107 +532 2 2 2 10 106 507 477 +533 2 2 2 10 514 356 445 +534 2 2 2 10 514 357 494 +535 2 2 2 10 342 517 380 +536 2 2 2 10 518 341 382 +537 2 2 2 10 108 521 107 +538 2 2 2 10 521 507 107 +539 2 2 2 10 426 483 344 +540 2 2 2 10 420 427 440 +541 2 2 2 10 429 445 356 +542 2 2 2 10 429 420 445 +543 2 2 2 10 454 461 336 +544 2 2 2 10 454 421 461 +545 2 2 2 10 442 435 362 +546 2 2 2 10 444 455 360 +547 2 2 2 10 444 423 455 +548 2 2 2 10 438 426 469 +549 2 2 2 10 452 450 362 +550 2 2 2 10 448 472 374 +551 2 2 2 10 448 428 472 +552 2 2 2 10 447 456 365 +553 2 2 2 10 447 429 456 +554 2 2 2 10 449 491 354 +555 2 2 2 10 449 430 491 +556 2 2 2 10 495 444 360 +557 2 2 2 10 430 444 495 +558 2 2 2 10 484 454 336 +559 2 2 2 10 434 454 484 +560 2 2 2 10 492 463 355 +561 2 2 2 10 437 463 492 +562 2 2 2 10 464 474 379 +563 2 2 2 10 453 469 344 +564 2 2 2 10 474 473 379 +565 2 2 2 10 440 473 474 +566 2 2 2 10 453 473 361 +567 2 2 2 10 453 441 473 +568 2 2 2 10 514 457 357 +569 2 2 2 10 445 457 514 +570 2 2 2 10 486 462 378 +571 2 2 2 10 446 462 486 +572 2 2 2 10 455 476 360 +573 2 2 2 10 455 451 476 +574 2 2 2 10 476 498 360 +575 2 2 2 10 466 456 506 +576 2 2 2 10 485 492 355 +577 2 2 2 10 485 457 492 +578 2 2 2 10 465 480 481 +579 2 2 2 10 490 477 507 +580 2 2 2 10 494 489 384 +581 2 2 2 10 484 489 494 +582 2 2 2 10 500 498 340 +583 2 2 2 10 495 498 500 +584 2 2 2 10 524 374 472 +585 2 2 2 10 524 472 512 +586 2 2 2 10 374 524 386 +587 2 2 2 10 105 106 477 +588 2 2 2 10 123 124 478 +589 2 2 2 10 19 497 18 +590 2 2 2 10 374 497 448 +591 2 2 2 10 496 26 27 +592 2 2 2 10 460 22 23 +593 2 2 2 10 482 91 90 +594 2 2 2 10 482 370 467 +595 2 2 2 10 503 447 365 +596 2 2 2 10 503 98 97 +597 2 2 2 10 451 508 366 +598 2 2 2 10 26 508 25 +599 2 2 2 10 110 493 109 +600 2 2 2 10 388 500 340 +601 2 2 2 10 514 506 356 +602 2 2 2 10 384 506 494 +603 2 2 2 10 494 506 514 +604 2 2 2 10 376 523 446 +605 2 2 2 10 489 523 384 +606 2 2 2 10 446 523 489 +607 2 2 2 10 87 519 88 +608 2 2 2 10 519 385 88 +609 2 2 2 10 524 512 391 +610 2 2 2 10 518 102 101 +611 2 2 2 10 342 387 517 +612 2 2 2 10 30 517 29 +613 2 2 2 10 517 387 29 +614 2 2 2 10 390 388 340 +615 2 2 2 10 513 388 390 +616 2 2 2 10 513 337 388 +617 2 2 2 10 480 337 513 +618 2 2 2 10 480 513 490 +619 2 2 2 10 459 368 438 +620 2 2 2 10 459 438 520 +621 2 2 2 10 511 342 380 +622 2 2 2 10 341 505 382 +623 2 2 2 10 449 371 332 +624 2 2 2 10 369 504 461 +625 2 2 2 10 378 504 121 +626 2 2 2 10 462 504 378 +627 2 2 2 10 462 461 504 +628 2 2 2 10 529 408 407 +629 2 2 2 10 530 393 409 +630 2 2 2 10 533 401 397 +631 2 2 2 10 536 470 531 +632 2 2 2 10 394 539 536 +633 2 2 2 10 540 346 348 +634 2 2 2 10 545 407 408 +635 2 2 2 10 407 545 542 +636 2 2 2 10 547 447 503 +637 2 2 2 10 413 548 414 +638 2 2 2 10 549 409 393 +639 2 2 2 10 555 393 530 +640 2 2 2 10 555 333 537 +641 2 2 2 10 564 401 533 +642 2 2 2 10 451 566 508 +643 2 2 2 10 567 406 526 +644 2 2 2 10 567 418 565 +645 2 2 2 10 569 408 419 +646 2 2 2 10 493 571 372 +647 2 2 2 10 572 71 70 +648 2 2 2 10 71 572 526 +649 2 2 2 10 393 575 549 +650 2 2 2 10 436 579 528 +651 2 2 2 10 581 408 529 +652 2 2 2 10 582 353 439 +653 2 2 2 10 583 447 547 +654 2 2 2 10 389 585 529 +655 2 2 2 10 586 91 482 +656 2 2 2 10 467 586 482 +657 2 2 2 10 589 69 68 +658 2 2 2 10 592 516 552 +659 2 2 2 10 418 594 565 +660 2 2 2 10 19 595 497 +661 2 2 2 10 595 448 497 +662 2 2 2 10 404 596 525 +663 2 2 2 10 436 597 363 +664 2 2 2 10 597 436 528 +665 2 2 2 10 522 598 533 +666 2 2 2 10 599 409 549 +667 2 2 2 10 333 600 537 +668 2 2 2 10 522 601 534 +669 2 2 2 10 451 603 566 +670 2 2 2 10 604 516 535 +671 2 2 2 10 605 352 424 +672 2 2 2 10 352 605 471 +673 2 2 2 10 392 608 546 +674 2 2 2 10 609 82 81 +675 2 2 2 10 611 416 538 +676 2 2 2 10 612 90 89 +677 2 2 2 10 612 373 482 +678 2 2 2 10 90 612 482 +679 2 2 2 10 615 467 363 +680 2 2 2 10 467 615 586 +681 2 2 2 10 479 616 365 +682 2 2 2 10 616 503 365 +683 2 2 2 10 617 335 541 +684 2 2 2 10 618 358 442 +685 2 2 2 10 618 431 593 +686 2 2 2 10 431 618 442 +687 2 2 2 10 483 621 344 +688 2 2 2 10 622 369 421 +689 2 2 2 10 422 623 488 +690 2 2 2 10 435 626 607 +691 2 2 2 10 627 431 364 +692 2 2 2 10 372 628 439 +693 2 2 2 10 628 372 571 +694 2 2 2 10 392 629 531 +695 2 2 2 10 630 505 478 +696 2 2 2 10 505 630 382 +697 2 2 2 10 124 630 478 +698 2 2 2 10 631 96 95 +699 2 2 2 10 96 631 547 +700 2 2 2 10 406 633 552 +701 2 2 2 10 635 331 488 +702 2 2 2 10 468 636 520 +703 2 2 2 10 487 637 530 +704 2 2 2 10 333 637 587 +705 2 2 2 10 508 638 366 +706 2 2 2 10 639 354 491 +707 2 2 2 10 433 639 491 +708 2 2 2 10 353 640 439 +709 2 2 2 10 640 415 439 +710 2 2 2 10 387 641 28 +711 2 2 2 10 642 332 625 +712 2 2 2 10 386 643 374 +713 2 2 2 10 643 497 374 +714 2 2 2 10 643 386 17 +715 2 2 2 10 381 646 65 +716 2 2 2 10 80 648 81 +717 2 2 2 10 69 649 70 +718 2 2 2 10 650 414 371 +719 2 2 2 10 449 650 371 +720 2 2 2 10 376 652 523 +721 2 2 2 10 654 420 429 +722 2 2 2 10 420 654 427 +723 2 2 2 10 413 657 548 +724 2 2 2 10 658 432 452 +725 2 2 2 10 659 460 603 +726 2 2 2 10 460 659 593 +727 2 2 2 10 417 660 426 +728 2 2 2 10 660 483 426 +729 2 2 2 10 370 661 467 +730 2 2 2 10 661 370 468 +731 2 2 2 10 663 447 583 +732 2 2 2 10 447 663 429 +733 2 2 2 10 666 437 474 +734 2 2 2 10 464 666 474 +735 2 2 2 10 334 669 440 +736 2 2 2 10 420 669 445 +737 2 2 2 10 669 420 440 +738 2 2 2 10 669 334 445 +739 2 2 2 10 670 118 119 +740 2 2 2 10 511 671 342 +741 2 2 2 10 331 672 422 +742 2 2 2 10 672 409 422 +743 2 2 2 10 673 427 654 +744 2 2 2 10 122 674 378 +745 2 2 2 10 674 486 378 +746 2 2 2 10 676 371 488 +747 2 2 2 10 678 407 542 +748 2 2 2 10 678 401 564 +749 2 2 2 10 679 425 339 +750 2 2 2 10 432 679 339 +751 2 2 2 10 680 470 536 +752 2 2 2 10 680 351 542 +753 2 2 2 10 423 681 442 +754 2 2 2 10 435 681 625 +755 2 2 2 10 681 435 442 +756 2 2 2 10 358 682 455 +757 2 2 2 10 451 682 603 +758 2 2 2 10 682 451 455 +759 2 2 2 10 335 683 541 +760 2 2 2 10 389 683 585 +761 2 2 2 10 481 684 372 +762 2 2 2 10 684 493 372 +763 2 2 2 10 16 685 15 +764 2 2 2 10 685 16 386 +765 2 2 2 10 94 689 95 +766 2 2 2 10 689 94 528 +767 2 2 2 10 120 690 119 +768 2 2 2 10 427 691 361 +769 2 2 2 10 693 425 679 +770 2 2 2 10 411 693 679 +771 2 2 2 10 511 694 477 +772 2 2 2 10 694 511 380 +773 2 2 2 10 694 105 477 +774 2 2 2 10 694 104 105 +775 2 2 2 10 380 104 694 +776 2 2 2 10 125 630 124 +777 2 2 2 10 125 382 630 +778 2 2 2 10 617 463 335 +779 2 2 2 10 649 572 70 +780 2 2 2 10 418 572 649 +781 2 2 2 10 621 441 344 +782 2 2 2 10 419 441 621 +783 2 2 2 10 668 693 367 +784 2 2 2 10 668 425 693 +785 2 2 2 10 512 425 668 +786 2 2 2 10 654 429 663 +787 2 2 2 10 582 439 628 +788 2 2 2 10 689 631 95 +789 2 2 2 10 468 338 661 +790 2 2 2 10 471 605 647 +791 2 2 2 10 648 609 81 +792 2 2 2 10 635 371 414 +793 2 2 2 10 488 371 635 +794 2 2 2 10 646 66 65 +795 2 2 2 10 597 615 363 +796 2 2 2 10 690 670 119 +797 2 2 2 10 501 670 690 +798 2 2 2 10 343 624 381 +799 2 2 2 10 646 375 499 +800 2 2 2 10 488 623 676 +801 2 2 2 10 99 665 100 +802 2 2 2 10 641 27 28 +803 2 2 2 10 496 27 641 +804 2 2 2 10 614 540 402 +805 2 2 2 10 567 572 418 +806 2 2 2 10 567 526 572 +807 2 2 2 10 528 579 689 +808 2 2 2 10 581 585 464 +809 2 2 2 10 581 529 585 +810 2 2 2 10 555 637 333 +811 2 2 2 10 555 530 637 +812 2 2 2 10 536 629 394 +813 2 2 2 10 536 531 629 +814 2 2 2 10 564 533 598 +815 2 2 2 10 574 534 601 +816 2 2 2 10 543 677 394 +817 2 2 2 10 552 619 406 +818 2 2 2 10 677 539 394 +819 2 2 2 10 680 539 351 +820 2 2 2 10 536 539 680 +821 2 2 2 10 680 545 470 +822 2 2 2 10 542 545 680 +823 2 2 2 10 558 614 402 +824 2 2 2 10 583 547 631 +825 2 2 2 10 599 549 647 +826 2 2 2 10 592 633 471 +827 2 2 2 10 592 552 633 +828 2 2 2 10 678 584 407 +829 2 2 2 10 564 584 678 +830 2 2 2 10 578 596 404 +831 2 2 2 10 606 623 422 +832 2 2 2 10 606 568 623 +833 2 2 2 10 578 670 501 +834 2 2 2 10 574 644 664 +835 2 2 2 10 583 620 663 +836 2 2 2 10 618 659 358 +837 2 2 2 10 618 593 659 +838 2 2 2 10 625 626 435 +839 2 2 2 10 659 682 358 +840 2 2 2 10 659 603 682 +841 2 2 2 10 642 681 423 +842 2 2 2 10 642 625 681 +843 2 2 2 10 351 553 542 +844 2 2 2 10 678 553 401 +845 2 2 2 10 542 553 678 +846 2 2 2 10 558 402 562 +847 2 2 2 10 348 577 540 +848 2 2 2 10 577 402 540 +849 2 2 2 10 421 645 653 +850 2 2 2 10 633 352 471 +851 2 2 2 10 352 633 565 +852 2 2 2 10 567 633 406 +853 2 2 2 10 567 565 633 +854 2 2 2 10 655 373 385 +855 2 2 2 10 519 655 385 +856 2 2 2 10 655 519 383 +857 2 2 2 10 109 493 684 +858 2 2 2 10 521 684 481 +859 2 2 2 10 684 521 108 +860 2 2 2 10 109 684 108 +861 2 2 2 10 662 479 466 +862 2 2 2 10 636 370 373 +863 2 2 2 10 370 636 468 +864 2 2 2 10 655 515 636 +865 2 2 2 10 373 655 636 +866 2 2 2 10 398 557 396 +867 2 2 2 10 398 563 557 +868 2 2 2 10 396 573 398 +869 2 2 2 10 454 645 421 +870 2 2 2 10 645 454 434 +871 2 2 2 10 560 113 114 +872 2 2 2 10 613 560 405 +873 2 2 2 10 562 114 115 +874 2 2 2 10 560 114 562 +875 2 2 2 10 405 560 562 +876 2 2 2 10 563 76 75 +877 2 2 2 10 556 76 563 +878 2 2 2 10 563 398 400 +879 2 2 2 10 400 556 563 +880 2 2 2 10 396 557 395 +881 2 2 2 10 72 559 73 +882 2 2 2 10 559 619 395 +883 2 2 2 10 556 77 76 +884 2 2 2 10 400 677 556 +885 2 2 2 10 543 556 677 +886 2 2 2 10 113 527 112 +887 2 2 2 10 113 560 527 +888 2 2 2 10 613 410 527 +889 2 2 2 10 527 560 613 +890 2 2 2 10 118 590 117 +891 2 2 2 10 118 670 590 +892 2 2 2 10 578 404 590 +893 2 2 2 10 578 590 670 +894 2 2 2 10 404 614 590 +895 2 2 2 10 558 590 614 +896 2 2 2 10 629 543 394 +897 2 2 2 10 526 72 71 +898 2 2 2 10 559 72 526 +899 2 2 2 10 406 619 526 +900 2 2 2 10 559 526 619 +901 2 2 2 10 561 110 111 +902 2 2 2 10 110 561 493 +903 2 2 2 10 571 493 561 +904 2 2 2 10 544 80 79 +905 2 2 2 10 648 80 544 +906 2 2 2 10 392 546 544 +907 2 2 2 10 544 546 648 +908 2 2 2 10 674 122 123 +909 2 2 2 10 674 478 486 +910 2 2 2 10 478 674 123 +911 2 2 2 10 94 93 528 +912 2 2 2 10 409 672 530 +913 2 2 2 10 672 487 530 +914 2 2 2 10 487 672 331 +915 2 2 2 10 635 414 548 +916 2 2 2 10 487 635 548 +917 2 2 2 10 635 487 331 +918 2 2 2 10 20 595 19 +919 2 2 2 10 660 345 483 +920 2 2 2 10 608 660 417 +921 2 2 2 10 345 621 483 +922 2 2 2 10 621 345 569 +923 2 2 2 10 419 621 569 +924 2 2 2 10 575 393 535 +925 2 2 2 10 516 575 535 +926 2 2 2 10 652 505 341 +927 2 2 2 10 505 652 376 +928 2 2 2 10 509 652 341 +929 2 2 2 10 92 91 586 +930 2 2 2 10 92 586 615 +931 2 2 2 10 622 501 369 +932 2 2 2 10 578 501 622 +933 2 2 2 10 578 622 596 +934 2 2 2 10 609 458 82 +935 2 2 2 10 355 656 434 +936 2 2 2 10 434 656 645 +937 2 2 2 10 397 576 533 +938 2 2 2 10 576 522 533 +939 2 2 2 10 613 405 554 +940 2 2 2 10 582 502 353 +941 2 2 2 10 17 18 643 +942 2 2 2 10 18 497 643 +943 2 2 2 10 647 592 471 +944 2 2 2 10 575 516 592 +945 2 2 2 10 575 592 549 +946 2 2 2 10 592 647 549 +947 2 2 2 10 614 404 525 +948 2 2 2 10 525 540 614 +949 2 2 2 10 395 619 570 +950 2 2 2 10 552 570 619 +951 2 2 2 10 333 587 644 +952 2 2 2 10 587 330 644 +953 2 2 2 10 688 411 424 +954 2 2 2 10 411 688 693 +955 2 2 2 10 693 688 367 +956 2 2 2 10 411 610 424 +957 2 2 2 10 354 650 449 +958 2 2 2 10 354 632 650 +959 2 2 2 10 414 650 413 +960 2 2 2 10 632 413 650 +961 2 2 2 10 522 576 601 +962 2 2 2 10 599 422 409 +963 2 2 2 10 606 422 599 +964 2 2 2 10 413 632 412 +965 2 2 2 10 443 632 354 +966 2 2 2 10 330 657 611 +967 2 2 2 10 611 412 416 +968 2 2 2 10 639 443 354 +969 2 2 2 10 667 417 368 +970 2 2 2 10 667 608 417 +971 2 2 2 10 667 546 608 +972 2 2 2 10 501 690 369 +973 2 2 2 10 690 504 369 +974 2 2 2 10 504 690 120 +975 2 2 2 10 616 98 503 +976 2 2 2 10 616 99 98 +977 2 2 2 10 340 510 390 +978 2 2 2 10 551 348 346 +979 2 2 2 10 551 349 348 +980 2 2 2 10 403 686 551 +981 2 2 2 10 676 332 371 +982 2 2 2 10 625 332 676 +983 2 2 2 10 625 676 626 +984 2 2 2 10 97 96 547 +985 2 2 2 10 503 97 547 +986 2 2 2 10 570 396 395 +987 2 2 2 10 332 642 449 +988 2 2 2 10 444 642 423 +989 2 2 2 10 430 642 444 +990 2 2 2 10 642 430 449 +991 2 2 2 10 512 375 391 +992 2 2 2 10 512 668 375 +993 2 2 2 10 345 531 470 +994 2 2 2 10 345 660 531 +995 2 2 2 10 608 392 531 +996 2 2 2 10 531 660 608 +997 2 2 2 10 408 569 545 +998 2 2 2 10 569 470 545 +999 2 2 2 10 470 569 345 +1000 2 2 2 10 490 671 477 +1001 2 2 2 10 671 511 477 +1002 2 2 2 10 671 490 513 +1003 2 2 2 10 671 513 390 +1004 2 2 2 10 333 644 600 +1005 2 2 2 10 600 644 574 +1006 2 2 2 10 574 601 600 +1007 2 2 2 10 638 26 496 +1008 2 2 2 10 26 638 508 +1009 2 2 2 10 641 387 510 +1010 2 2 2 10 496 641 510 +1011 2 2 2 10 584 389 529 +1012 2 2 2 10 407 584 529 +1013 2 2 2 10 24 25 566 +1014 2 2 2 10 25 508 566 +1015 2 2 2 10 576 399 537 +1016 2 2 2 10 399 576 397 +1017 2 2 2 10 576 537 600 +1018 2 2 2 10 576 600 601 +1019 2 2 2 10 666 335 437 +1020 2 2 2 10 666 683 335 +1021 2 2 2 10 666 464 585 +1022 2 2 2 10 666 585 683 +1023 2 2 2 10 593 22 460 +1024 2 2 2 10 431 627 593 +1025 2 2 2 10 23 24 566 +1026 2 2 2 10 23 603 460 +1027 2 2 2 10 566 603 23 +1028 2 2 2 10 353 687 443 +1029 2 2 2 10 502 687 353 +1030 2 2 2 10 412 687 416 +1031 2 2 2 10 634 416 687 +1032 2 2 2 10 502 634 687 +1033 2 2 2 10 443 640 353 +1034 2 2 2 10 443 639 640 +1035 2 2 2 10 639 433 640 +1036 2 2 2 10 673 691 427 +1037 2 2 2 10 509 341 518 +1038 2 2 2 10 389 584 580 +1039 2 2 2 10 580 584 564 +1040 2 2 2 10 564 598 580 +1041 2 2 2 10 419 581 379 +1042 2 2 2 10 581 419 408 +1043 2 2 2 10 581 464 379 +1044 2 2 2 10 385 612 89 +1045 2 2 2 10 385 373 612 +1046 2 2 2 10 412 657 413 +1047 2 2 2 10 611 657 412 +1048 2 2 2 10 554 695 613 +1049 2 2 2 10 347 696 351 +1050 2 2 2 10 696 553 351 +1051 2 2 2 10 696 347 588 +1052 2 2 2 10 697 396 570 +1053 2 2 2 10 396 697 573 +1054 2 2 2 10 698 100 665 +1055 2 2 2 10 509 698 665 +1056 2 2 2 10 699 677 400 +1057 2 2 2 10 700 602 695 +1058 2 2 2 10 527 701 112 +1059 2 2 2 10 561 701 591 +1060 2 2 2 10 702 361 473 +1061 2 2 2 10 702 440 427 +1062 2 2 2 10 440 702 473 +1063 2 2 2 10 361 702 427 +1064 2 2 2 10 393 703 535 +1065 2 2 2 10 399 703 537 +1066 2 2 2 10 703 399 535 +1067 2 2 2 10 704 610 606 +1068 2 2 2 10 599 704 606 +1069 2 2 2 10 83 705 84 +1070 2 2 2 10 705 83 458 +1071 2 2 2 10 401 706 397 +1072 2 2 2 10 706 401 553 +1073 2 2 2 10 708 399 397 +1074 2 2 2 10 709 21 22 +1075 2 2 2 10 709 593 627 +1076 2 2 2 10 593 709 22 +1077 2 2 2 10 516 711 552 +1078 2 2 2 10 711 570 552 +1079 2 2 2 10 711 516 604 +1080 2 2 2 10 342 712 387 +1081 2 2 2 10 712 510 387 +1082 2 2 2 10 713 551 686 +1083 2 2 2 10 551 713 349 +1084 2 2 2 10 550 713 686 +1085 2 2 2 10 714 506 384 +1086 2 2 2 10 714 662 466 +1087 2 2 2 10 506 714 466 +1088 2 2 2 10 662 715 479 +1089 2 2 2 10 715 665 479 +1090 2 2 2 10 716 350 538 +1091 2 2 2 10 416 716 538 +1092 2 2 2 10 717 515 655 +1093 2 2 2 10 383 717 655 +1094 2 2 2 10 502 718 634 +1095 2 2 2 10 565 720 352 +1096 2 2 2 10 720 565 594 +1097 2 2 2 10 721 510 340 +1098 2 2 2 10 544 722 392 +1099 2 2 2 10 722 629 392 +1100 2 2 2 10 723 469 453 +1101 2 2 2 10 469 723 338 +1102 2 2 2 10 724 632 443 +1103 2 2 2 10 724 687 412 +1104 2 2 2 10 687 724 443 +1105 2 2 2 10 632 724 412 +1106 2 2 2 10 86 726 5 +1107 2 2 2 10 87 726 519 +1108 2 2 2 10 726 87 5 +1109 2 2 2 10 15 727 2 +1110 2 2 2 10 727 63 2 +1111 2 2 2 10 728 348 349 +1112 2 2 2 10 728 554 577 +1113 2 2 2 10 348 728 577 +1114 2 2 2 10 729 75 74 +1115 2 2 2 10 729 557 563 +1116 2 2 2 10 75 729 563 +1117 2 2 2 10 555 703 393 +1118 2 2 2 10 555 537 703 +1119 2 2 2 10 706 708 397 +1120 2 2 2 10 706 588 708 +1121 2 2 2 10 377 705 458 +1122 2 2 2 10 410 695 602 +1123 2 2 2 10 410 613 695 +1124 2 2 2 10 398 699 400 +1125 2 2 2 10 398 573 699 +1126 2 2 2 10 696 706 553 +1127 2 2 2 10 696 588 706 +1128 2 2 2 10 700 718 602 +1129 2 2 2 10 523 714 384 +1130 2 2 2 10 720 424 352 +1131 2 2 2 10 688 424 720 +1132 2 2 2 10 424 610 704 +1133 2 2 2 10 63 727 343 +1134 2 2 2 10 685 727 15 +1135 2 2 2 10 350 716 700 +1136 2 2 2 10 634 716 416 +1137 2 2 2 10 718 716 634 +1138 2 2 2 10 700 716 718 +1139 2 2 2 10 698 101 100 +1140 2 2 2 10 101 698 518 +1141 2 2 2 10 698 509 518 +1142 2 2 2 10 582 718 502 +1143 2 2 2 10 715 509 665 +1144 2 2 2 10 715 652 509 +1145 2 2 2 10 665 99 616 +1146 2 2 2 10 616 479 665 +1147 2 2 2 10 510 712 390 +1148 2 2 2 10 712 671 390 +1149 2 2 2 10 671 712 342 +1150 2 2 2 10 699 539 677 +1151 2 2 2 10 448 595 364 +1152 2 2 2 10 708 535 399 +1153 2 2 2 10 535 708 604 +1154 2 2 2 10 667 648 546 +1155 2 2 2 10 424 704 605 +1156 2 2 2 10 599 647 605 +1157 2 2 2 10 704 599 605 +1158 2 2 2 10 85 383 86 +1159 2 2 2 10 383 726 86 +1160 2 2 2 10 383 519 726 +1161 2 2 2 10 710 346 475 +1162 2 2 2 10 475 651 532 +1163 2 2 2 10 532 710 475 +1164 2 2 2 10 588 347 604 +1165 2 2 2 10 604 708 588 +1166 2 2 2 10 597 93 92 +1167 2 2 2 10 92 615 597 +1168 2 2 2 10 597 528 93 +1169 2 2 2 10 481 480 521 +1170 2 2 2 10 480 490 521 +1171 2 2 2 10 490 507 521 +1172 2 2 2 10 459 515 377 +1173 2 2 2 10 459 520 515 +1174 2 2 2 10 515 520 636 +1175 2 2 2 10 607 626 568 +1176 2 2 2 10 626 623 568 +1177 2 2 2 10 676 623 626 +1178 2 2 2 10 663 620 654 +1179 2 2 2 10 722 543 629 +1180 2 2 2 10 111 112 701 +1181 2 2 2 10 561 111 701 +1182 2 2 2 10 594 692 367 +1183 2 2 2 10 688 594 367 +1184 2 2 2 10 594 688 720 +1185 2 2 2 10 620 689 579 +1186 2 2 2 10 689 620 583 +1187 2 2 2 10 583 631 689 +1188 2 2 2 10 628 571 561 +1189 2 2 2 10 591 628 561 +1190 2 2 2 10 628 591 582 +1191 2 2 2 10 707 499 692 +1192 2 2 2 10 700 719 350 +1193 2 2 2 10 554 719 695 +1194 2 2 2 10 719 554 728 +1195 2 2 2 10 719 728 349 +1196 2 2 2 10 695 719 700 +1197 2 2 2 10 355 463 617 +1198 2 2 2 10 656 355 617 +1199 2 2 2 10 656 617 651 +1200 2 2 2 10 727 624 343 +1201 2 2 2 10 624 685 386 +1202 2 2 2 10 685 624 727 +1203 2 2 2 10 596 622 421 +1204 2 2 2 10 653 596 421 +1205 2 2 2 10 596 653 525 +1206 2 2 2 10 562 402 405 +1207 2 2 2 10 402 577 405 +1208 2 2 2 10 405 577 554 +1209 2 2 2 10 532 675 403 +1210 2 2 2 10 607 568 658 +1211 2 2 2 10 657 330 587 +1212 2 2 2 10 657 487 548 +1213 2 2 2 10 657 637 487 +1214 2 2 2 10 657 587 637 +1215 2 2 2 10 710 532 403 +1216 2 2 2 10 551 710 403 +1217 2 2 2 10 710 551 346 +1218 2 2 2 10 436 673 579 +1219 2 2 2 10 436 691 673 +1220 2 2 2 10 579 673 620 +1221 2 2 2 10 620 673 654 +1222 2 2 2 10 21 627 20 +1223 2 2 2 10 20 627 595 +1224 2 2 2 10 595 627 364 +1225 2 2 2 10 709 627 21 +1226 2 2 2 10 338 730 661 +1227 2 2 2 10 375 731 391 +1228 2 2 2 10 732 361 691 +1229 2 2 2 10 475 733 651 +1230 2 2 2 10 733 656 651 +1231 2 2 2 10 734 617 541 +1232 2 2 2 10 675 734 541 +1233 2 2 2 10 617 734 651 +1234 2 2 2 10 735 436 363 +1235 2 2 2 10 436 735 691 +1236 2 2 2 10 467 736 363 +1237 2 2 2 10 736 467 661 +1238 2 2 2 10 500 737 359 +1239 2 2 2 10 737 500 388 +1240 2 2 2 10 459 738 368 +1241 2 2 2 10 738 667 368 +1242 2 2 2 10 740 646 499 +1243 2 2 2 10 707 740 499 +1244 2 2 2 10 646 740 66 +1245 2 2 2 10 741 527 410 +1246 2 2 2 10 741 591 701 +1247 2 2 2 10 591 741 410 +1248 2 2 2 10 527 741 701 +1249 2 2 2 10 742 351 539 +1250 2 2 2 10 699 742 539 +1251 2 2 2 10 743 438 469 +1252 2 2 2 10 438 743 520 +1253 2 2 2 10 338 743 469 +1254 2 2 2 10 640 744 415 +1255 2 2 2 10 744 640 433 +1256 2 2 2 10 658 745 432 +1257 2 2 2 10 411 745 610 +1258 2 2 2 10 73 746 74 +1259 2 2 2 10 746 73 559 +1260 2 2 2 10 747 719 349 +1261 2 2 2 10 591 748 582 +1262 2 2 2 10 748 718 582 +1263 2 2 2 10 748 591 410 +1264 2 2 2 10 749 522 534 +1265 2 2 2 10 522 749 598 +1266 2 2 2 10 750 525 653 +1267 2 2 2 10 606 751 568 +1268 2 2 2 10 751 658 568 +1269 2 2 2 10 751 606 610 +1270 2 2 2 10 679 745 411 +1271 2 2 2 10 679 432 745 +1272 2 2 2 10 723 730 338 +1273 2 2 2 10 468 743 338 +1274 2 2 2 10 468 520 743 +1275 2 2 2 10 713 747 349 +1276 2 2 2 10 713 550 747 +1277 2 2 2 10 736 735 363 +1278 2 2 2 10 746 395 557 +1279 2 2 2 10 559 395 746 +1280 2 2 2 10 749 580 598 +1281 2 2 2 10 744 465 415 +1282 2 2 2 10 602 748 410 +1283 2 2 2 10 602 718 748 +1284 2 2 2 10 734 532 651 +1285 2 2 2 10 675 532 734 +1286 2 2 2 10 337 737 388 +1287 2 2 2 10 737 433 359 +1288 2 2 2 10 745 751 610 +1289 2 2 2 10 745 658 751 +1290 2 2 2 10 732 691 735 +1291 2 2 2 10 730 736 661 +1292 2 2 2 10 747 350 719 +1293 2 2 2 10 739 403 675 +1294 2 2 2 10 725 739 675 +1295 2 2 2 10 351 742 347 +1296 2 2 2 10 742 573 347 +1297 2 2 2 10 573 742 699 +1298 2 2 2 10 750 733 475 +1299 2 2 2 10 733 645 656 +1300 2 2 2 10 645 733 653 +1301 2 2 2 10 653 733 750 +1302 2 2 2 10 697 347 573 +1303 2 2 2 10 347 697 604 +1304 2 2 2 10 604 697 711 +1305 2 2 2 10 711 697 570 +1306 2 2 2 10 624 731 381 +1307 2 2 2 10 731 646 381 +1308 2 2 2 10 646 731 375 +1309 2 2 2 10 638 721 366 +1310 2 2 2 10 721 638 496 +1311 2 2 2 10 510 721 496 +1312 2 2 2 10 544 79 722 +1313 2 2 2 10 524 391 386 +1314 2 2 2 10 386 391 624 +1315 2 2 2 10 624 391 731 +1316 2 2 2 10 453 361 723 +1317 2 2 2 10 361 732 723 +1318 2 2 2 10 732 730 723 +1319 2 2 2 10 435 607 362 +1320 2 2 2 10 607 452 362 +1321 2 2 2 10 607 658 452 +1322 2 2 2 10 686 739 534 +1323 2 2 2 10 739 686 403 +1324 2 2 2 10 739 749 534 +1325 2 2 2 10 750 346 540 +1326 2 2 2 10 346 750 475 +1327 2 2 2 10 525 750 540 +1328 2 2 2 10 562 116 558 +1329 2 2 2 10 116 562 115 +1330 2 2 2 10 499 668 367 +1331 2 2 2 10 692 499 367 +1332 2 2 2 10 668 499 375 +1333 2 2 2 10 652 714 523 +1334 2 2 2 10 715 662 652 +1335 2 2 2 10 652 662 714 +1336 2 2 2 10 340 498 721 +1337 2 2 2 10 476 366 721 +1338 2 2 2 10 476 721 498 +1339 2 2 2 10 104 380 103 +1340 2 2 2 10 517 103 380 +1341 2 2 2 10 692 594 589 +1342 2 2 2 10 389 580 725 +1343 2 2 2 10 725 683 389 +1344 2 2 2 10 725 541 683 +1345 2 2 2 10 725 675 541 +1346 2 2 2 10 377 717 705 +1347 2 2 2 10 515 717 377 +1348 2 2 2 10 707 692 589 +1349 2 2 2 10 746 729 74 +1350 2 2 2 10 557 729 746 +1351 2 2 2 10 740 67 66 +1352 2 2 2 10 707 67 740 +1353 2 2 2 10 707 68 67 +1354 2 2 2 10 589 68 707 +1355 2 2 2 10 428 752 339 +1356 2 2 2 10 452 752 450 +1357 2 2 2 10 752 452 339 +1358 2 2 2 10 752 428 450 +1359 2 2 2 10 753 85 84 +1360 2 2 2 10 753 717 383 +1361 2 2 2 10 85 753 383 +1362 2 2 2 10 418 754 594 +1363 2 2 2 10 754 589 594 +1364 2 2 2 10 754 418 649 +1365 2 2 2 10 754 69 589 +1366 2 2 2 10 649 69 754 +1367 2 2 2 10 705 753 84 +1368 2 2 2 10 705 717 753 +1369 2 2 2 10 722 79 78 +1370 2 2 2 10 730 732 736 +1371 2 2 2 10 732 735 736 +1372 2 2 2 10 574 550 534 +1373 2 2 2 10 550 686 534 +1374 2 2 2 10 664 550 574 +1375 2 2 2 10 749 725 580 +1376 2 2 2 10 739 725 749 +1377 2 2 2 10 458 738 459 +1378 2 2 2 10 738 458 609 +1379 2 2 2 10 648 667 738 +1380 2 2 2 10 648 738 609 +1381 2 2 2 10 558 117 590 +1382 2 2 2 10 558 116 117 +1383 2 2 2 10 744 337 465 +1384 2 2 2 10 337 744 737 +1385 2 2 2 10 744 433 737 +1386 2 2 2 10 755 442 362 +1387 2 2 2 10 755 450 431 +1388 2 2 2 10 450 755 362 +1389 2 2 2 10 442 755 431 +1390 2 2 2 10 339 756 472 +1391 2 2 2 10 512 756 425 +1392 2 2 2 10 756 512 472 +1393 2 2 2 10 756 339 425 +1394 2 2 2 10 664 644 330 +1395 2 2 2 10 330 611 664 +1396 2 2 2 10 664 611 538 +1397 2 2 2 10 556 757 77 +1398 2 2 2 10 757 556 543 +1399 2 2 2 10 664 758 550 +1400 2 2 2 10 758 747 550 +1401 2 2 2 10 758 664 538 +1402 2 2 2 10 350 758 538 +1403 2 2 2 10 350 747 758 +1404 2 2 2 10 757 722 78 +1405 2 2 2 10 722 757 543 +1406 2 2 2 10 77 757 78 +1407 2 2 2 10 102 759 6 +1408 2 2 2 10 759 126 6 +1409 2 2 2 10 760 30 3 +1410 2 2 2 10 760 103 517 +1411 2 2 2 10 103 760 3 +1412 2 2 2 10 30 760 517 +1413 2 2 2 10 759 125 126 +1414 2 2 2 10 759 518 382 +1415 2 2 2 10 518 759 102 +1416 2 2 2 10 382 125 759 +$EndElements 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 3fe488131..864920a23 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,138 +1,184 @@ /** * @file test_build_neighborhood_parallel.cc * @author Aurelia Isabel Cuba Ramos * @date Sun Oct 11 11:20:23 2015 * * @brief test in parallel for the class NonLocalNeighborhood * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" -#include "test_material_damage.hh" +#include "test_material.hh" #include "non_local_neighborhood_base.hh" #include "dumper_paraview.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { akantu::initialize("material_parallel_test.dat", argc, argv); StaticCommunicator & comm = akantu::StaticCommunicator::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); akantu::MeshPartition * partition = NULL; if(prank == 0) { - mesh.read("fine_mesh.msh"); + mesh.read("parallel_test.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } /// model creation SolidMechanicsModel model(mesh); model.initParallel(partition); delete partition; /// dump the ghost elements before the non-local part is intialized DumperParaview dumper_ghost("ghost_elements"); dumper_ghost.registerMesh(mesh, spatial_dimension, _ghost); if(psize > 1) { dumper_ghost.dump(); } /// creation of material selector MeshDataMaterialSelector * mat_selector; mat_selector = new MeshDataMaterialSelector("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(SolidMechanicsModelOptions(_static, true)); - model.registerNewCustomMaterials< TestMaterialDamage >("test_material"); + model.registerNewCustomMaterials< TestMaterial >("test_material"); model.initMaterials(); /// 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 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) { Material & mat = model.getMaterial(m); Array & grad_u = const_cast &> (mat.getInternal("grad_u")(element_type, ghost_type)); Array::iterator< Matrix > grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); Array::iterator< Matrix > grad_u_end = grad_u.end(spatial_dimension, spatial_dimension); - /// apply different strain in the first element on each partition - if (grad_u_it != grad_u_end) { - (*grad_u_it) += (2. *applied_strain); - ++grad_u_it; - } for (; grad_u_it != grad_u_end; ++grad_u_it) (*grad_u_it) += 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"); + mesh.initElementTypeMapArray(quad_coords, spatial_dimension, spatial_dimension, false, _ek_regular, true); + model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); + + Vector 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 & coords = quad_coords(type, _not_ghost); + Array::const_vector_iterator coord_it = coords.begin(spatial_dimension); + for (UInt e = 0; e < nb_elements; ++e) { + for (UInt q = 0; q < nb_quads; ++q, ++coord_it) { + Real dist = center.distance(*coord_it); + if (dist < min_distance) { + min_distance = dist; + q_min.element = e; + q_min.num_point = q; + q_min.global_num = nb_elements * nb_quads + q; + q_min.type = type; + } + } + } + } + + Real global_min = min_distance; + comm.allReduce(&global_min, 1, _so_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 & grad_u = const_cast &> (mat.getInternal("grad_u")(q_min.type, _not_ghost)); + Array::iterator< Matrix > grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); + grad_u_it += local_num; + Matrix & g_u = *grad_u_it; + g_u += applied_strain; + } + /// compute the non-local strains model.getNonLocalManager().computeAllNonLocalStresses(); - model.dump(); - + 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 & damage = const_cast &> (mat.getInternal("damage")(q_min.type, _not_ghost)); + Real * dam_ptr = damage.storage(); + dam_ptr += local_num; + *dam_ptr = 0.9; + } - /// print results to screen for validation - // std::ifstream quad_pairs; - // quad_pairs.open("quadrature_pairs.0"); - // std::string current_line; - // while(getline(quad_pairs, current_line)) - // std::cout << current_line << std::endl; - // quad_pairs.close(); - // std::ifstream neighborhoods; - // neighborhoods.open("neighborhoods.0"); - // while(getline(neighborhoods, current_line)) - // std::cout << current_line << std::endl; - // neighborhoods.close(); + /// compute the non-local strains + model.getNonLocalManager().computeAllNonLocalStresses(); + model.dump(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.sh b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.sh new file mode 100755 index 000000000..b0914c1d6 --- /dev/null +++ b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +mpirun -np 10 ./test_build_neighborhood_parallel diff --git a/test/test_model/test_non_local_toolbox/test_material.cc b/test/test_model/test_non_local_toolbox/test_material.cc index c84df9bc2..c73a76737 100644 --- a/test/test_model/test_non_local_toolbox/test_material.cc +++ b/test/test_model/test_non_local_toolbox/test_material.cc @@ -1,122 +1,122 @@ /** * @file test_material.cc * @author Aurelia Isabel Cuba Ramos * @date Wed Sep 23 17:16:30 2015 * * @brief Implementation of test material for the non-local neighborhood base test * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "test_material.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template TestMaterial::TestMaterial(SolidMechanicsModel & model, const ID & id) : Material(model, id), - MyElasticParent(model, id), + MyLocalParent(model, id), MyNonLocalParent(model, id), grad_u_nl("grad_u non local", *this) { this->is_non_local = true; this->grad_u_nl.initialize(dim*dim); this->model->getNonLocalManager().registerNonLocalVariable(this->gradu.getName(), grad_u_nl.getName(), dim*dim); } /* -------------------------------------------------------------------------- */ template void TestMaterial::initMaterial() { AKANTU_DEBUG_IN(); this->registerNeighborhood(); - MyElasticParent::initMaterial(); + MyLocalParent::initMaterial(); MyNonLocalParent::initMaterial(); this->model->getNonLocalManager().nonLocalVariableToNeighborhood(grad_u_nl.getName(), "test_region"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void TestMaterial::insertQuadsInNeighborhoods(GhostType ghost_type) { /// this function will add all the quadrature points to the same /// default neighborhood instead of using one neighborhood per /// material NonLocalManager & manager = this->model->getNonLocalManager(); InternalField quadrature_points_coordinates("quadrature_points_coordinates_tmp_nl", *this); quadrature_points_coordinates.initialize(spatial_dimension); /// intialize quadrature point object IntegrationPoint q; q.ghost_type = ghost_type; q.kind = _ek_regular; Mesh::type_iterator it = this->element_filter.firstType(spatial_dimension, ghost_type, _ek_regular); Mesh::type_iterator last_type = this->element_filter.lastType(spatial_dimension, ghost_type, _ek_regular); for(; it != last_type; ++it) { q.type = *it; const Array & elem_filter = this->element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if(nb_element) { UInt nb_quad = this->fem->getNbIntegrationPoints(*it, ghost_type); UInt nb_tot_quad = nb_quad * nb_element; Array & quads = quadrature_points_coordinates(*it, ghost_type); quads.resize(nb_tot_quad); this->model->getFEEngine().computeIntegrationPointsCoordinates(quads, *it, ghost_type, elem_filter); Array::const_vector_iterator quad = quads.begin(spatial_dimension); UInt * elem = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e) { q.element = *elem; for (UInt nq = 0; nq < nb_quad; ++nq) { q.num_point = nq; q.global_num = q.element * nb_quad + nq; manager.insertQuad(q, *quad, "test_region"); ++quad; } ++elem; } } } } /* -------------------------------------------------------------------------- */ template void TestMaterial::registerNeighborhood() { this->model->getNonLocalManager().registerNeighborhood("test_region", "test_region"); } /* -------------------------------------------------------------------------- */ // Instantiate the material for the 3 dimensions INSTANTIATE_MATERIAL(TestMaterial); /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/test/test_model/test_non_local_toolbox/test_material.hh b/test/test_model/test_non_local_toolbox/test_material.hh index 81e9e86a4..b8785f23e 100644 --- a/test/test_model/test_non_local_toolbox/test_material.hh +++ b/test/test_model/test_non_local_toolbox/test_material.hh @@ -1,75 +1,75 @@ /** * @file test_material.hh * @author Aurelia Isabel Cuba Ramos * @date Wed Sep 23 17:16:30 2015 * * @brief test material for the non-local neighborhood base test * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ -#include "material_elastic.hh" +#include "material_damage.hh" #include "material_non_local.hh" #ifndef __TEST_MATERIAL_HH__ #define __TEST_MATERIAL_HH__ __BEGIN_AKANTU__ template -class TestMaterial : public MaterialElastic, +class TestMaterial : public MaterialDamage, public MaterialNonLocal{ /* -------------------------------------------------------------------------- */ /* Constructor/Destructor */ /* -------------------------------------------------------------------------- */ public: TestMaterial(SolidMechanicsModel & model, const ID & id); virtual ~TestMaterial() {}; typedef MaterialNonLocal MyNonLocalParent; - typedef MaterialElastic MyElasticParent; + typedef MaterialDamage MyLocalParent; /* -------------------------------------------------------------------------- */ /* Methods */ /* -------------------------------------------------------------------------- */ public: void initMaterial(); void computeNonLocalStresses(GhostType ghost_type) {}; void insertQuadsInNeighborhoods(GhostType ghost_type); virtual void registerNeighborhood(); protected: /* -------------------------------------------------------------------------- */ /* Members */ /* -------------------------------------------------------------------------- */ private: InternalField grad_u_nl; }; __END_AKANTU__ #endif /* __TEST_MATERIAL_HH__ */ 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 new file mode 100644 index 000000000..f8b955f44 --- /dev/null +++ b/test/test_model/test_non_local_toolbox/test_pair_computation.cc @@ -0,0 +1,216 @@ +/** + * @file test_pair_computation.cc + * @author Aurelia Isabel Cuba Ramos + * @date Tue Nov 24 10:33:55 2015 + * + * @brief test the weight computation with and without grid + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model.hh" +#include "test_material_damage.hh" +#include "non_local_manager.hh" +#include "non_local_neighborhood.hh" +#include "dumper_paraview.hh" +/* -------------------------------------------------------------------------- */ +using namespace akantu; +typedef std::vector< std::pair > PairList; + +/* -------------------------------------------------------------------------- */ +void computePairs(SolidMechanicsModel & model, PairList * pair_list); +int main(int argc, char *argv[]) { + akantu::initialize("material_remove_damage.dat", argc, argv); + + // some configuration variables + const UInt spatial_dimension = 2; + + StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + Int psize = comm.getNbProc(); + Int prank = comm.whoAmI(); + + // mesh creation and read + Mesh mesh(spatial_dimension); + akantu::MeshPartition * partition = NULL; + if(prank == 0) { + mesh.read("pair_test.msh"); + /// partition the mesh + partition = new MeshPartitionScotch(mesh, spatial_dimension); + partition->partitionate(psize); + } + + /// model creation + SolidMechanicsModel model(mesh); + model.initParallel(partition); + delete partition; + + /// creation of material selector + MeshDataMaterialSelector * mat_selector; + mat_selector = new MeshDataMaterialSelector("physical_names", model); + model.setMaterialSelector(*mat_selector); + + /// model initialization changed to use our material + model.initFull(SolidMechanicsModelOptions(_static, true)); + model.registerNewCustomMaterials< TestMaterialDamage >("test_material"); + model.initMaterials(); + /// 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); + + NonLocalManager & manager = model.getNonLocalManager(); + const PairList * pairs_mat_1 = manager.getNeighborhood("mat_1").getPairLists(); + const PairList * pairs_mat_2 = manager.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) { + std::pair p = (pairs_mat_1[0])[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) { + std::pair p = (pairs_mat_2[0])[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) { + std::pair p = (pairs_mat_1[1])[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) { + std::pair p = (pairs_mat_2[1])[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 EXIT_SUCCESS; +} + +/* -------------------------------------------------------------------------- */ +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"); + mesh.initElementTypeMapArray(quad_coords, spatial_dimension, spatial_dimension, false, _ek_regular, true); + model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); + + /// loop in a n^2 way over all the quads to generate the pairs + Real neighborhood_radius = 0.5; + Mesh::type_iterator it_1 = mesh.firstType(spatial_dimension, _not_ghost, kind); + Mesh::type_iterator last_type_1 = mesh.lastType(spatial_dimension, _not_ghost, kind); + IntegrationPoint q1; + IntegrationPoint q2; + q1.kind = kind; + q2.kind = kind; + GhostType ghost_type_1 = _not_ghost; + q1.ghost_type = ghost_type_1; + Vector q1_coords(spatial_dimension); + Vector 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 & quad_coords_1 = quad_coords(q1.type, q1.ghost_type); + Array::const_vector_iterator coord_it_1 = quad_coords_1.begin(spatial_dimension); + for (UInt e_1 = 0; e_1 < nb_elements_1; ++e_1) { + q1.element = e_1; + UInt mat_index_1 = model.getMaterialByElement(q1.type, q1.ghost_type).begin()[q1.element]; + for (UInt q_1 = 0; q_1 < nb_quads_1; ++q_1) { + q1.global_num = nb_quads_1 * e_1 + q_1; + q1.num_point = q_1; + q1_coords = coord_it_1[q1.global_num]; + /// loop over all other quads and create pairs for this given quad + for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { + GhostType ghost_type_2 = *gt; + q2.ghost_type = ghost_type_2; + Mesh::type_iterator it_2 = mesh.firstType(spatial_dimension, ghost_type_2, kind); + Mesh::type_iterator last_type_2 = mesh.lastType(spatial_dimension, ghost_type_2, kind); + for(; it_2 != last_type_2 ; ++it_2) { + ElementType type_2 = *it_2; + q2.type = type_2; + UInt nb_elements_2 = mesh.getNbElement(type_2, ghost_type_2); + UInt nb_quads_2 = model.getFEEngine().getNbIntegrationPoints(type_2); + Array & quad_coords_2 = quad_coords(q2.type, q2.ghost_type); + Array::const_vector_iterator coord_it_2 = quad_coords_2.begin(spatial_dimension); + for (UInt e_2 = 0; e_2 < nb_elements_2; ++e_2) { + q2.element = e_2; + UInt mat_index_2 = model.getMaterialByElement(q2.type, q2.ghost_type).begin()[q2.element]; + for (UInt q_2 = 0; q_2 < nb_quads_2; ++q_2) { + q2.global_num = nb_quads_2 * e_2 + q_2; + q2.num_point = q_2; + q2_coords = coord_it_2[q2.global_num]; + Real distance = q1_coords.distance(q2_coords); + if (mat_index_1 != mat_index_2) + continue; + else if(distance <= neighborhood_radius + Math::getTolerance() && + (q2.ghost_type == _ghost || + (q2.ghost_type == _not_ghost && q1.global_num <= q2.global_num))) { // storing only half lists + pair_list[q2.ghost_type].push_back(std::make_pair(q1, q2)); + } + } + } + } + } + } + } + } +} diff --git a/test/test_model/test_non_local_toolbox/test_pair_computation.sh b/test/test_model/test_non_local_toolbox/test_pair_computation.sh new file mode 100755 index 000000000..84dee8dd6 --- /dev/null +++ b/test/test_model/test_non_local_toolbox/test_pair_computation.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +./test_pair_computation +mpirun -np 4 ./test_pair_computation diff --git a/test/test_model/test_solid_mechanics_model/material_elastic_plane_strain.dat b/test/test_model/test_solid_mechanics_model/material_elastic_plane_strain.dat index 15d295fca..b7297c018 100644 --- a/test/test_model/test_solid_mechanics_model/material_elastic_plane_strain.dat +++ b/test/test_model/test_solid_mechanics_model/material_elastic_plane_strain.dat @@ -1,9 +1,9 @@ -parser_permissive = true +permissive_parser = true material elastic [ name = steel rho = 7800 # density E = 2.1e11 # young's modulus nu = 0.3 # poisson's ratio Plane_Stress = 0 # plane strain ] diff --git a/test/test_model/test_solid_mechanics_model/patch_tests/data/material_check_stress_plane_strain.dat b/test/test_model/test_solid_mechanics_model/patch_tests/data/material_check_stress_plane_strain.dat index 15d295fca..b7297c018 100644 --- a/test/test_model/test_solid_mechanics_model/patch_tests/data/material_check_stress_plane_strain.dat +++ b/test/test_model/test_solid_mechanics_model/patch_tests/data/material_check_stress_plane_strain.dat @@ -1,9 +1,9 @@ -parser_permissive = true +permissive_parser = true material elastic [ name = steel rho = 7800 # density E = 2.1e11 # young's modulus nu = 0.3 # poisson's ratio Plane_Stress = 0 # plane strain ]