diff --git a/src/model/contact_mechanics/contact_mechanics_model.cc b/src/model/contact_mechanics/contact_mechanics_model.cc index fd4533968..c50187f91 100644 --- a/src/model/contact_mechanics/contact_mechanics_model.cc +++ b/src/model/contact_mechanics/contact_mechanics_model.cc @@ -1,591 +1,596 @@ /** * @file coontact_mechanics_model.cc * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Wed Feb 21 2018 * * @brief Contact mechanics model * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "contact_mechanics_model.hh" #include "boundary_condition_functor.hh" #include "dumpable_inline_impl.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ContactMechanicsModel::ContactMechanicsModel( Mesh & mesh, Array<Real> & positions, UInt dim, const ID & id, const MemoryID & memory_id, std::shared_ptr<DOFManager> dof_manager, const ModelType model_type) : Model(mesh, model_type, dof_manager, dim, id, memory_id), current_positions(positions) { AKANTU_DEBUG_IN(); this->registerFEEngineObject<MyFEEngineType>("ContactMechanicsModel", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("contact_mechanics", id, true); this->mesh.addDumpMeshToDumper("contact_mechanics", mesh, Model::spatial_dimension, _not_ghost, _ek_regular); #endif this->registerDataAccessor(*this); this->detector = std::make_unique<ContactDetector>(this->mesh, current_positions, id + ":contact_detector"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ContactMechanicsModel::ContactMechanicsModel( Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id, std::shared_ptr<DOFManager> dof_manager, const ModelType model_type) : ContactMechanicsModel(mesh, mesh.getNodes(), dim, id, memory_id, dof_manager, model_type) {} /* -------------------------------------------------------------------------- */ ContactMechanicsModel::~ContactMechanicsModel() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::initFullImpl(const ModelOptions & options) { Model::initFullImpl(options); // initalize the resolutions if (this->parser.getLastParsedFile() != "") { this->instantiateResolutions(); } this->initResolutions(); this->initBC(*this, *displacement, *displacement_increment, *external_force); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::instantiateResolutions() { ParserSection model_section; bool is_empty; std::tie(model_section, is_empty) = this->getParserSection(); if (not is_empty) { auto model_resolutions = model_section.getSubSections(ParserType::_contact_resolution); for (const auto & section : model_resolutions) { this->registerNewResolution(section); } } auto sub_sections = this->parser.getSubSections(ParserType::_contact_resolution); for (const auto & section : sub_sections) { this->registerNewResolution(section); } if (resolutions.empty()) AKANTU_EXCEPTION("No contact resolutions where instantiated for the model" << getID()); are_resolutions_instantiated = true; } /* -------------------------------------------------------------------------- */ Resolution & ContactMechanicsModel::registerNewResolution(const ParserSection & section) { std::string res_name; std::string res_type = section.getName(); std::string opt_param = section.getOption(); try { std::string tmp = section.getParameter("name"); res_name = tmp; /** this can seem weird, but there is an ambiguous operator * overload that i couldn't solve. @todo remove the * weirdness of this code */ } catch (debug::Exception &) { AKANTU_ERROR("A contact resolution of type \'" << res_type << "\' in the input file has been defined without a name!"); } Resolution & res = this->registerNewResolution(res_name, res_type, opt_param); res.parseSection(section); return res; } /* -------------------------------------------------------------------------- */ Resolution & ContactMechanicsModel::registerNewResolution( const ID & res_name, const ID & res_type, const ID & opt_param) { AKANTU_DEBUG_ASSERT(resolutions_names_to_id.find(res_name) == resolutions_names_to_id.end(), "A resolution with this name '" << res_name << "' has already been registered. " << "Please use unique names for resolutions"); UInt res_count = resolutions.size(); resolutions_names_to_id[res_name] = res_count; std::stringstream sstr_res; sstr_res << this->id << ":" << res_count << ":" << res_type; ID res_id = sstr_res.str(); std::unique_ptr<Resolution> resolution = ResolutionFactory::getInstance().allocate(res_type, spatial_dimension, opt_param, *this, res_id); resolutions.push_back(std::move(resolution)); return *(resolutions.back()); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::initResolutions() { AKANTU_DEBUG_ASSERT(resolutions.size() != 0, "No resolutions to initialize !"); if (!are_resolutions_instantiated) instantiateResolutions(); // \TODO check if each resolution needs a initResolution() method } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::initModel() { getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ FEEngine & ContactMechanicsModel::getFEEngineBoundary(const ID & name) { return dynamic_cast<FEEngine &>( getFEEngineClassBoundary<MyFEEngineType>(name)); } /* -------------------------------------------------------------------------- */ -void ContactMechanicsModel::initSolver( - TimeStepSolverType /*time_step_solver_type*/, NonLinearSolverType) { +void ContactMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type, + NonLinearSolverType) { + + auto & dof_manager = this->getDOFManager(); + + /* -------------------------------------------------------------------------- */ + // for alloc type of solvers this->allocNodalField(this->displacement, spatial_dimension, "displacement"); this->allocNodalField(this->displacement_increment, spatial_dimension, "displacement_increment"); - this->allocNodalField(this->contact_force, spatial_dimension, - "contact_force"); + this->allocNodalField(this->internal_force, spatial_dimension, + "internal_force"); this->allocNodalField(this->external_force, spatial_dimension, "external_force"); this->allocNodalField(this->normals, spatial_dimension, "normals"); this->allocNodalField(this->gaps, 1, "gaps"); this->allocNodalField(this->nodal_area, 1, "areas"); this->allocNodalField(this->blocked_dofs, 1, "blocked_dofs"); } /* -------------------------------------------------------------------------- */ std::tuple<ID, TimeStepSolverType> ContactMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_contact: { return std::make_tuple("explicit_contact", _tsst_dynamic); } case _implicit_contact: { return std::make_tuple("implicit_contact", _tsst_static); } default: return std::make_tuple("unkown", _tsst_not_defined); } } /* -------------------------------------------------------------------------- */ ModelSolverOptions ContactMechanicsModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_dynamic: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } case _tsst_static: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); break; } return options; } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::assembleResidual() { AKANTU_DEBUG_IN(); /* ------------------------------------------------------------------------ */ // computes the internal forces this->assembleInternalForces(); + /* ------------------------------------------------------------------------ */ + this->getDOFManager().assembleToResidual("displacement", *this->internal_force, + 1); + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::assembleInternalForces() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the contact forces"); // assemble the forces due to local stresses auto assemble = [&](auto && ghost_type) { for (auto & resolution : resolutions) { resolution->assembleInternalForces(ghost_type); } }; AKANTU_DEBUG_INFO("Assemble residual for local elements"); assemble(_not_ghost); // assemble the stresses due to ghost elements AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); assemble(_ghost); - /* ------------------------------------------------------------------------ */ - this->getDOFManager().assembleToResidual("displacement", *this->contact_force, - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::search() { this->detector->search(this->contact_map); this->assembleFieldsFromContactMap(); this->computeNodalAreas<Surface::slave>(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::search(Array<Real> & increment) { this->detector->search(this->contact_map); for (auto & entry : contact_map) { auto & element = entry.second; const auto & connectivity = element.connectivity; auto master_node = connectivity[1]; Vector<Real> u(spatial_dimension); for (UInt s : arange(spatial_dimension)) { u(s) = increment(master_node, s); } u *= -1.0; const auto & normal = element.normal; Real uv = Math::vectorDot(u.storage(), normal.storage(), spatial_dimension); if (uv + element.gap <= 0) { element.gap = abs(uv + element.gap); } else { element.gap = 0.0; } } this->assembleFieldsFromContactMap(); this->computeNodalAreas<Surface::slave>(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::assembleFieldsFromContactMap() { if (this->contact_map.empty()) AKANTU_ERROR( "Contact map is empty, Please run search before assembling the fields"); for (auto & entry : contact_map) { const auto & element = entry.second; auto connectivity = element.connectivity; auto node = connectivity(0); (*gaps)[node] = element.gap; for (UInt i = 0; i < spatial_dimension; ++i) (*normals)(node, i) = element.normal[i]; } } /* -------------------------------------------------------------------------- */ template <Surface id> void ContactMechanicsModel::computeNodalAreas() { this->nodal_area->clear(); this->external_force->clear(); this->applyBC( BC::Neumann::FromHigherDim(Matrix<Real>::eye(spatial_dimension, 1)), this->detector->getSurfaceId<id>()); for (auto && tuple : zip(*nodal_area, make_view(*external_force, spatial_dimension))) { auto & area = std::get<0>(tuple); auto & force = std::get<1>(tuple); for (auto & f : force) area += pow(f, 2); area = sqrt(area); } this->external_force->clear(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::beforeSolveStep() { this->search(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::afterSolveStep() {} /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Contact Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << Model::spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + resolutions [" << std::endl; for (auto & resolution : resolutions) { resolution->printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ MatrixType ContactMechanicsModel::getMatrixType(const ID & matrix_id) { if (matrix_id == "K") return _symmetric; return _mt_not_defined; } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix"); if (!this->getDOFManager().hasMatrix("K")) { this->getDOFManager().getNewMatrix("K", getMatrixType("K")); } - this->getDOFManager().clearMatrix("K"); + //this->getDOFManager().clearMatrix("K"); for (auto & resolution : resolutions) { resolution->assembleStiffnessMatrix(_not_ghost); } } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::assembleLumpedMatrix(const ID & /*matrix_id*/) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * ContactMechanicsModel::createNodalFieldBool(const std::string & /*field_name*/, const std::string & /*group_name*/, bool /*padding_flag*/) { dumper::Field * field = nullptr; return field; } /* -------------------------------------------------------------------------- */ dumper::Field * ContactMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string, Array<Real> *> real_nodal_fields; - real_nodal_fields["contact_force"] = this->contact_force; - real_nodal_fields["external_force"] = this->external_force; + real_nodal_fields["contact_force"] = this->internal_force; real_nodal_fields["blocked_dofs"] = this->blocked_dofs; real_nodal_fields["normals"] = this->normals; real_nodal_fields["gaps"] = this->gaps; real_nodal_fields["areas"] = this->nodal_area; dumper::Field * field = nullptr; if (padding_flag) field = this->mesh.createNodalField(real_nodal_fields[field_name], group_name, 3); else field = this->mesh.createNodalField(real_nodal_fields[field_name], group_name); return field; } #else /* -------------------------------------------------------------------------- */ dumper::Field * ContactMechanicsModel::createNodalFieldReal( __attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return nullptr; } #endif /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::dump(const std::string & dumper_name) { mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::dump(const std::string & dumper_name, UInt step) { mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void ContactMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) { mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::dump() { mesh.dump(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::dump(UInt step) { mesh.dump(step); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::dump(Real time, UInt step) { mesh.dump(time, step); } /* -------------------------------------------------------------------------- */ UInt ContactMechanicsModel::getNbData( const Array<Element> & elements, const SynchronizationTag & /*tag*/) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes_per_element = 0; for (const Element & el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::packData(CommunicationBuffer & /*buffer*/, const Array<Element> & /*elements*/, const SynchronizationTag & /*tag*/) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::unpackData(CommunicationBuffer & /*buffer*/, const Array<Element> & /*elements*/, const SynchronizationTag & /*tag*/) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt ContactMechanicsModel::getNbData( const Array<UInt> & dofs, const SynchronizationTag & /*tag*/) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); AKANTU_DEBUG_OUT(); return size * dofs.size(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::packData(CommunicationBuffer & /*buffer*/, const Array<UInt> & /*dofs*/, const SynchronizationTag & /*tag*/) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ContactMechanicsModel::unpackData(CommunicationBuffer & /*buffer*/, const Array<UInt> & /*dofs*/, const SynchronizationTag & /*tag*/) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/contact_mechanics/contact_mechanics_model.hh b/src/model/contact_mechanics/contact_mechanics_model.hh index 181d78cba..9f5b43973 100644 --- a/src/model/contact_mechanics/contact_mechanics_model.hh +++ b/src/model/contact_mechanics/contact_mechanics_model.hh @@ -1,325 +1,325 @@ /** * @file contact_mechanics_model.hh * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Wed Feb 21 2018 * * @brief Model of Contact Mechanics * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "contact_detector.hh" #include "data_accessor.hh" #include "fe_engine.hh" #include "model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_CONTACT_MECHANICS_MODEL_HH__ #define __AKANTU_CONTACT_MECHANICS_MODEL_HH__ namespace akantu { class Resolution; template <ElementKind kind, class IntegrationOrderFunctor> class IntegratorGauss; template <ElementKind kind> class ShapeLagrange; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ class ContactMechanicsModel : public Model, public DataAccessor<Element>, public DataAccessor<UInt>, public BoundaryCondition<ContactMechanicsModel> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ using MyFEEngineType = FEEngineTemplate<IntegratorGauss, ShapeLagrange>; public: ContactMechanicsModel( Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "contact_mechanics_model", const MemoryID & memory_id = 0, std::shared_ptr<DOFManager> dof_manager = nullptr, const ModelType model_type = ModelType::_contact_mechanics_model); ContactMechanicsModel( Mesh & mesh, Array<Real> & positions, UInt spatial_dimension = _all_dimensions, const ID & id = "contact_mechanics_model", const MemoryID & memory_id = 0, std::shared_ptr<DOFManager> dof_manager = nullptr, const ModelType model_type = ModelType::_contact_mechanics_model); ~ContactMechanicsModel() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize completely the model void initFullImpl(const ModelOptions & options) override; /// allocate all vectors void initSolver(TimeStepSolverType, NonLinearSolverType) override; /// initialize all internal arrays for resolutions void initResolutions(); /// initialize the modelType void initModel() override; /// call back for the solver, computes the force residual void assembleResidual() override; /// get the type of matrix needed MatrixType getMatrixType(const ID & matrix_id) override; /// callback for the solver, this assembles different matrices void assembleMatrix(const ID & matrix_id) override; /// callback for the solver, this assembles the stiffness matrix void assembleLumpedMatrix(const ID & matrix_id) override; /// get some default values for derived classes std::tuple<ID, TimeStepSolverType> getDefaultSolverID(const AnalysisMethod & method) override; ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const; /// callback for the solver, this is called at beginning of solve void beforeSolveStep() override; /// callback for the solver, this is called at end of solve void afterSolveStep() override; /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; /* ------------------------------------------------------------------------ */ /* Contact Detection */ /* ------------------------------------------------------------------------ */ public: void search(); void search(Array<Real> &); template <Surface id> void computeNodalAreas(); void assembleFieldsFromContactMap(); /* ------------------------------------------------------------------------ */ /* Contact Resolution */ /* ------------------------------------------------------------------------ */ public: /// register an empty contact resolution of a given type Resolution & registerNewResolution(const ID & res_name, const ID & res_type, const ID & opt_param); protected: /// register a resolution in the dynamic database Resolution & registerNewResolution(const ParserSection & res_section); /// read the resolution files to instantiate all the resolutions void instantiateResolutions(); /* ------------------------------------------------------------------------ */ /* Solver Interface */ /* ------------------------------------------------------------------------ */ public: /// assembles the contact stiffness matrix virtual void assembleStiffnessMatrix(); /// assembles the contant internal forces virtual void assembleInternalForces(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: FEEngine & getFEEngineBoundary(const ID & name = "") override; /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) override; dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) override; void dump() override; virtual void dump(UInt step); virtual void dump(Real time, UInt step); virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; UInt getNbData(const Array<UInt> & dofs, const SynchronizationTag & tag) const override; void packData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) const override; void unpackData(CommunicationBuffer & buffer, const Array<UInt> & dofs, const SynchronizationTag & tag) override; protected: /// contact detection class friend class ContactDetector; /// contact resolution class friend class Resolution; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt); /// get the ContactMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array<Real> &); /// get the ContactMechanicsModel::increment vector \warn only consistent /// if ContactMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *displacement_increment, Array<Real> &); - /// get the ContactMechanics::contact_force vector (internal forces) - AKANTU_GET_MACRO(InternalForce, *contact_force, Array<Real> &); + /// get the ContactMechanics::internal_force vector (internal forces) + AKANTU_GET_MACRO(InternalForce, *internal_force, Array<Real> &); /// get the ContactMechanicsModel::external_force vector (external forces) AKANTU_GET_MACRO(ExternalForce, *external_force, Array<Real> &); /// get the ContactMechanicsModel::force vector (external forces) Array<Real> & getForce() { AKANTU_DEBUG_WARNING("getForce was maintained for backward compatibility, " "use getExternalForce instead"); return *external_force; } /// get the ContactMechanics::blocked_dofs vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<Real> &); /// get the ContactMechanics::gaps (contact gaps) AKANTU_GET_MACRO(Gaps, *gaps, Array<Real> &); /// get the ContactMechanics::normals (normals on slave nodes) AKANTU_GET_MACRO(Normals, *normals, Array<Real> &); /// get the ContactMechanics::areas (nodal areas) AKANTU_GET_MACRO(NodalArea, *nodal_area, Array<Real> &); - /// get the ContactMechanics::contact_force vector (internal forces) + /// get the ContactMechanics::internal_force vector (internal forces) AKANTU_GET_MACRO(CurrentPositions, current_positions, Array<Real> &); /// get the contat map inline std::map<UInt, ContactElement> & getContactMap() { return contact_map; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// tells if the resolutions are instantiated bool are_resolutions_instantiated; /// displacements array Array<Real> * displacement; /// increment of displacement Array<Real> * displacement_increment{nullptr}; /// contact forces array - Array<Real> * contact_force{nullptr}; + Array<Real> * internal_force{nullptr}; /// external forces array Array<Real> * external_force{nullptr}; /// boundary vector Array<Real> * blocked_dofs{nullptr}; /// gaps Array<Real> * gaps{nullptr}; /// normals Array<Real> * normals{nullptr}; /// tangents Array<Real> * tangents{nullptr}; /// nodal areas Array<Real> * nodal_area{nullptr}; /// array of current position used during update residual Array<Real> & current_positions; /// contact detection std::unique_ptr<ContactDetector> detector; /// list of contact resolutions std::vector<std::unique_ptr<Resolution>> resolutions; /// mapping between resolution name and resolution internal id std::map<std::string, UInt> resolutions_names_to_id; /// mapping between slave node its respective contact element std::map<UInt, ContactElement> contact_map; }; } // namespace akantu /* ------------------------------------------------------------------------ */ /* inline functions */ /* ------------------------------------------------------------------------ */ #include "parser.hh" #include "resolution.hh" /* ------------------------------------------------------------------------ */ #endif /* __AKANTU_CONTACT_MECHANICS_MODEL_HH__ */ diff --git a/src/model/contact_mechanics/resolution.cc b/src/model/contact_mechanics/resolution.cc index 85e718cc3..c3ce6db6f 100644 --- a/src/model/contact_mechanics/resolution.cc +++ b/src/model/contact_mechanics/resolution.cc @@ -1,356 +1,357 @@ /** * @file resolution.cc * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Mon Jan 7 2019 * @date last modification: Mon Jan 7 2019 * * @brief Implementation of common part of the contact resolution class * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "resolution.hh" #include "contact_mechanics_model.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Resolution::Resolution(ContactMechanicsModel & model, const ID & id) : Memory(id, model.getMemoryID()), Parsable(ParserType::_contact_resolution, id), fem(model.getFEEngine()), name(""), model(model), spatial_dimension(model.getMesh().getSpatialDimension()){ AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Resolution::~Resolution() = default; /* -------------------------------------------------------------------------- */ void Resolution::initialize() { registerParam("name", name, std::string(), _pat_parsable | _pat_readable); registerParam("mu", mu, Real(0.), _pat_parsable | _pat_modifiable, "Friciton Coefficient"); } /* -------------------------------------------------------------------------- */ void Resolution::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 << "Contact Resolution " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void Resolution::assembleInternalForces(GhostType /*ghost_type*/) { AKANTU_DEBUG_IN(); auto & internal_force = const_cast<Array<Real> &>(model.getInternalForce()); const auto local_nodes = model.getMesh().getElementGroup(name).getNodes(); auto & nodal_area = const_cast<Array<Real> &>(model.getNodalArea()); auto & contact_map = model.getContactMap(); for (auto & slave: local_nodes) { if (contact_map.find(slave) == contact_map.end()) continue; auto & element = contact_map[slave]; const auto & conn = element.connectivity; const auto & type = element.master.type; auto nb_nodes_master = Mesh::getNbNodesPerElement(type); Vector<Real> shapes(nb_nodes_master); Matrix<Real> dnds(spatial_dimension - 1, nb_nodes_master); #define GET_SHAPES_NATURAL(type) \ ElementClass<type>::computeShapes(element.projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPES_NATURAL); #undef GET_SHAPES_NATURAL #define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass<type>::computeDNDS(element.projection, dnds) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL Vector<Real> fc(conn.size() * spatial_dimension); - Matrix<Real> surface_matrix(spatial_dimension - 1, spatial_dimension - 1); - computeSurfaceMatrix(element.tangents, surface_matrix); + Matrix<Real> m_alpha_beta(spatial_dimension - 1, spatial_dimension - 1); + computeMetricTensor(element.tangents, m_alpha_beta); Vector<Real> n(conn.size() * spatial_dimension); computeN(n, shapes, element.normal); computeNormalForce(fc, n, element.gap); Array<Real> t_alpha(conn.size() * spatial_dimension, spatial_dimension - 1); Array<Real> n_alpha(conn.size() * spatial_dimension, spatial_dimension - 1); Array<Real> d_alpha(conn.size() * spatial_dimension, spatial_dimension - 1); computeTalpha(t_alpha, shapes, element.tangents); computeNalpha(n_alpha, dnds, element.normal); - computeDalpha(d_alpha, n_alpha, t_alpha, surface_matrix, element.gap); + computeDalpha(d_alpha, n_alpha, t_alpha, m_alpha_beta, element.gap); //computeFrictionForce(fc, d_alpha, gap); UInt nb_degree_of_freedom = internal_force.getNbComponent(); for (UInt i = 0; i < conn.size(); ++i) { UInt n = conn[i]; for (UInt j = 0; j < nb_degree_of_freedom; ++j) { UInt offset_node = n * nb_degree_of_freedom + j; internal_force[offset_node] += fc[i*nb_degree_of_freedom + j]; internal_force[offset_node] *= nodal_area[n]; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Resolution::assembleStiffnessMatrix(GhostType /*ghost_type*/) { AKANTU_DEBUG_IN(); auto & stiffness = const_cast<SparseMatrix &>(model.getDOFManager().getMatrix("K")); const auto local_nodes = model.getMesh().getElementGroup(name).getNodes(); auto & nodal_area = const_cast<Array<Real> &>(model.getNodalArea()); auto & contact_map = model.getContactMap(); for (auto & slave: local_nodes) { if (contact_map.find(slave) == contact_map.end()) { continue; } auto & master = contact_map[slave].master; auto & gap = contact_map[slave].gap; auto & projection = contact_map[slave].projection; auto & normal = contact_map[slave].normal; const auto & connectivity = contact_map[slave].connectivity; const ElementType & type = master.type; UInt nb_nodes_master = Mesh::getNbNodesPerElement(master.type); Vector<Real> shapes(nb_nodes_master); Matrix<Real> shapes_derivatives(spatial_dimension - 1, nb_nodes_master); #define GET_SHAPES_NATURAL(type) \ ElementClass<type>::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPES_NATURAL); #undef GET_SHAPES_NATURAL #define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass<type>::computeDNDS(projection, shapes_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL Matrix<Real> elementary_stiffness(connectivity.size() * spatial_dimension, connectivity.size() * spatial_dimension); Matrix<Real> tangents(spatial_dimension - 1, spatial_dimension); Matrix<Real> global_coords(nb_nodes_master, spatial_dimension); computeCoordinates(master, global_coords); computeTangents(shapes_derivatives, global_coords, tangents); - Matrix<Real> surface_matrix(spatial_dimension - 1, spatial_dimension - 1); - computeSurfaceMatrix(tangents, surface_matrix); + Matrix<Real> m_alpha_beta(spatial_dimension - 1, spatial_dimension - 1); + computeMetricTensor(tangents, m_alpha_beta); Vector<Real> n(connectivity.size() * spatial_dimension); Array<Real> t_alpha(connectivity.size() * spatial_dimension, spatial_dimension - 1); Array<Real> n_alpha(connectivity.size() * spatial_dimension, spatial_dimension - 1); Array<Real> d_alpha(connectivity.size() * spatial_dimension, spatial_dimension - 1); computeN( n, shapes, normal); computeTalpha( t_alpha, shapes, tangents); computeNalpha( n_alpha, shapes_derivatives, normal); - computeDalpha( d_alpha, n_alpha, t_alpha, surface_matrix, gap); - + computeDalpha( d_alpha, n_alpha, t_alpha, m_alpha_beta, gap); + + /* Array<Real> t_alpha_beta(conn.size() * spatial_dimension, (spatial_dimension - 1) * (spatial_dimension -1)); Array<Real> n_alpha_beta(conn.size() * spatial_dimension, (spatial_dimension - 1) * (spatial_dimension -1)); Array<Real> p_alpha(conn.size() * spatial_dimension, spatial_dimension - 1); - + */ Matrix<Real> kc(connectivity.size() * spatial_dimension, connectivity.size() * spatial_dimension); - computeTangentModuli(kc, n, n_alpha, d_alpha, surface_matrix, gap); + computeTangentModuli(kc, n, n_alpha, d_alpha, m_alpha_beta, gap); std::vector<UInt> equations; UInt nb_degree_of_freedom = model.getSpatialDimension(); std::vector<Real> areas; for (UInt i : arange(connectivity.size())) { UInt n = connectivity[i]; for (UInt j : arange(nb_degree_of_freedom)) { equations.push_back(n * nb_degree_of_freedom + j); areas.push_back(nodal_area[n]); } } for (UInt i : arange(kc.rows())) { UInt row = equations[i]; for (UInt j : arange(kc.cols())) { UInt col = equations[j]; kc(i, j) *= areas[i]; stiffness.add(row, col, kc(i, j)); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Resolution::computeTangents(Matrix<Real> & shapes_derivatives, Matrix<Real> & global_coords, Matrix<Real> & tangents) { tangents.mul<false, false>(shapes_derivatives, global_coords); } /* -------------------------------------------------------------------------- */ -void Resolution::computeSurfaceMatrix(Matrix<Real> & tangents, Matrix<Real> & surface_matrix) { +void Resolution::computeMetricTensor(Matrix<Real> & tangents, Matrix<Real> & m_alpha_beta) { - surface_matrix.mul<false, true>(tangents, tangents); - surface_matrix = surface_matrix.inverse(); + m_alpha_beta.mul<false, true>(tangents, tangents); + m_alpha_beta = m_alpha_beta.inverse(); } /* -------------------------------------------------------------------------- */ void Resolution::computeN(Vector<Real> & n, Vector<Real> & shapes, Vector<Real> & normal) { UInt dim = normal.size(); for (UInt i = 0; i < dim; ++i) { n[i] = normal[i]; for (UInt j = 0; j < shapes.size(); ++j) { n[(1 + j) * dim + i] = -normal[i] * shapes[j]; } } } /* -------------------------------------------------------------------------- */ void Resolution::computeTalpha(Array<Real> & t_alpha, Vector<Real> & shapes, Matrix<Real> & tangents) { t_alpha.clear(); for (auto && values: zip(tangents.transpose(), make_view(t_alpha, t_alpha.size()))) { auto & tangent = std::get<0>(values); auto & t_s = std::get<1>(values); for (UInt i : arange(spatial_dimension)) { t_s[i] = -tangent(i); for (UInt j : arange(shapes.size())) { t_s[(1 + j)*spatial_dimension + i] = -shapes[j] * tangent(i); } } } } /* -------------------------------------------------------------------------- */ void Resolution::computeNalpha(Array<Real> & n_alpha, Matrix<Real> & shapes_derivatives, Vector<Real> & normal) { n_alpha.clear(); for (auto && values: zip(shapes_derivatives.transpose(), make_view(n_alpha, n_alpha.size()))) { auto & dnds = std::get<0>(values); auto & n_s = std::get<1>(values); for (UInt i : arange(spatial_dimension)) { n_s[i] = 0; for (UInt j : arange(dnds.size())) { n_s[(1 + j)*spatial_dimension + i] = -dnds(j)*normal[i]; } } } } /* -------------------------------------------------------------------------- */ void Resolution::computeDalpha(Array<Real> & d_alpha, Array<Real> & n_alpha, - Array<Real> & t_alpha, Matrix<Real> & surface_matrix, + Array<Real> & t_alpha, Matrix<Real> & m_alpha_beta, Real & gap) { d_alpha.clear(); - for (auto && entry : zip(surface_matrix.transpose(), + for (auto && entry : zip(m_alpha_beta.transpose(), make_view(d_alpha, d_alpha.size()))) { auto & a_s = std::get<0>(entry); auto & d_s = std::get<1>(entry); for (auto && values : zip(arange(t_alpha.size()), make_view(t_alpha, t_alpha.size()), make_view(n_alpha, n_alpha.size()))) { auto & index = std::get<0>(values); auto & t_s = std::get<1>(values); auto & n_s = std::get<2>(values); d_s += (t_s + gap * n_s); d_s *= a_s(index); } } } /* -------------------------------------------------------------------------- */ void Resolution::computeCoordinates(const Element & el, Matrix<Real> & coords) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type); Vector<UInt> connect = model.getMesh().getConnectivity(el.type, _not_ghost) .begin(nb_nodes_per_element)[el.element]; // change this to current position auto & positions = model.getMesh().getNodes(); for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connect[n]; for (UInt s: arange(spatial_dimension)) { coords(n, s) = positions(node, s); } } } } // akantu diff --git a/src/model/contact_mechanics/resolution.hh b/src/model/contact_mechanics/resolution.hh index 8051d9428..67984d34a 100644 --- a/src/model/contact_mechanics/resolution.hh +++ b/src/model/contact_mechanics/resolution.hh @@ -1,230 +1,231 @@ /** * @file resolution.hh * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Mon Jan 7 2019 * @date last modification: Mon Jan 7 2019 * * @brief Mother class for all contact resolutions * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "aka_memory.hh" #include "parsable.hh" #include "parser.hh" #include "fe_engine.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_RESOLUTION_HH__ #define __AKANTU_RESOLUTION_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Model; class ContactMechanicsModel; } // namespace akantu namespace akantu { /** * Interface of all contact resolutions * Prerequisites for a new resolution * - inherit from this class * - implement the following methods: * \code * * virtual void computeNormalForce(); * virtual void computeFrictionForce(); * * \endcode * */ class Resolution : public Memory, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructor/Destructor */ /* ------------------------------------------------------------------------ */ public: /// instantiate contact resolution with defaults Resolution(ContactMechanicsModel & model, const ID & id = ""); /// Destructor ~Resolution() override; protected: void initialize(); /// computes coordinates of a given element void computeCoordinates(const Element & , Matrix<Real> &); /// computes tangents - void computeTangents(Matrix<Real> & /* shapes_derivatives */, - Matrix<Real> & /* global_coords */, - Matrix<Real> & /* tangents */); + void computeTangents(Matrix<Real> & , + Matrix<Real> & , + Matrix<Real> & ); - /// computes surface metric matrix - void computeSurfaceMatrix(Matrix<Real> & /* tangents */, - Matrix<Real> & /* surface_matrix */); + /// computes metric tensor (@f$m_{\alpha\beta}@f$) where @f$\alpha, + /// \beta@f$ are surface directions + void computeMetricTensor(Matrix<Real> &, + Matrix<Real> &); /// computes N array - void computeN(Vector<Real> & /* n */, - Vector<Real> & /* shapes */, - Vector<Real> & /* normal */); + void computeN(Vector<Real> &, + Vector<Real> &, + Vector<Real> &); - /// computes N_{\alpha} where \alpha is number of surface dimensions - void computeNalpha(Array<Real> & /* n_alpha */, - Matrix<Real> & /* shapes_derivatives */, - Vector<Real> & /* normal */); + /// computes (@f$N_{\alpha}@f$) where \alpha is surface dimension + void computeNalpha(Array<Real> &, + Matrix<Real> &, + Vector<Real> &); - /// computes T_{\alpha} where \alpha is surface dimenion + /// computes (@f$T_{\alpha}@f$) where @f$\alpha@f$ is surface dimension void computeTalpha(Array<Real> & , Vector<Real> & , Matrix<Real> & ); - /// computes D_{\alpha} where \alpha is number of surface dimensions - void computeDalpha(Array<Real> & /* d_alpha */, - Array<Real> & /* n_alpha */, - Array<Real> & /* t_alpha */, - Matrix<Real> & /* surface_matrix */, - Real & /* gap */); + /// computes (@f$D_{\alpha}@f$) where @f$\alpha@f$ is surface dimension + void computeDalpha(Array<Real> & , + Array<Real> & , + Array<Real> & , + Matrix<Real> &, + Real & ); /* ------------------------------------------------------------------------ */ /* Functions that resolutions can/should reimplement */ /* ------------------------------------------------------------------------ */ protected: /// computes the normal force virtual void computeNormalForce(__attribute__((unused)) Vector<Real> & /* force */, __attribute__((unused)) Vector<Real> & /* n */, __attribute__((unused)) Real & /* gap */) { AKANTU_TO_IMPLEMENT(); } /// computes the friction force virtual void computeFrictionForce(__attribute__((unused)) Vector<Real> & /* force */, __attribute__((unused)) Array<Real> & /* d_alpha */, __attribute__((unused)) Real & /* gap */) { AKANTU_TO_IMPLEMENT(); } /// compute the tangent moduli virtual void computeTangentModuli(__attribute__((unused)) Matrix<Real> &, __attribute__((unused)) Vector<Real> & /* n */, __attribute__((unused)) Array<Real> & /* n_alpha */, __attribute__((unused)) Array<Real> & /* d_alpha */, __attribute__((unused)) Matrix<Real> & /* A */, __attribute__((unused)) Real & /* gap */) { AKANTU_TO_IMPLEMENT(); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// assemble the residual for this resolution void assembleInternalForces(GhostType ghost_type); /// assemble the stiffness matrix for this resolution void assembleStiffnessMatrix(GhostType ghost_type); public: /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Link to the fem object in the model FEEngine & fem; /// resolution name std::string name; /// model to which the resolution belong ContactMechanicsModel & model; /// friciton coefficient : mu Real mu; /// spatial dimension UInt spatial_dimension; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Resolution & _this) { _this.printself(stream); return stream; } } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { using ResolutionFactory = Factory<Resolution, ID, UInt, const ID &, ContactMechanicsModel &, const ID &>; /// macaulay bracket to convert positive gap to zero template <typename T> T macaulay(T var) {return var < 0 ? 0 : var; } template <typename T> T heaviside(T var) {return var < 0 ? 0 : 1; } } // namespace akantu #define INSTANTIATE_RESOLUTION_ONLY(res_name) \ class res_name #define RESOLUTION_DEFAULT_PER_DIM_ALLOCATOR(id, res_name) \ [](UInt dim, const ID &, ContactMechanicsModel & model, \ const ID & id) -> std::unique_ptr<Resolution> { \ switch (dim) { \ case 1: \ return std::make_unique<res_name>(model, id); \ case 2: \ return std::make_unique<res_name>(model, id); \ case 3: \ return std::make_unique<res_name>(model, id); \ default: \ AKANTU_EXCEPTION("The dimension " \ << dim << "is not a valid dimension for the contact resolution " \ << #id); \ } \ } #define INSTANTIATE_RESOLUTION(id, res_name) \ INSTANTIATE_RESOLUTION_ONLY(res_name); \ static bool resolution_is_alocated_##id[[gnu::unused]] = \ ResolutionFactory::getInstance().registerAllocator( \ #id, RESOLUTION_DEFAULT_PER_DIM_ALLOCATOR(id, res_name)) #endif /* __AKANTU_RESOLUTION_HH__ */ diff --git a/src/model/contact_mechanics/resolutions/resolution_penalty.cc b/src/model/contact_mechanics/resolutions/resolution_penalty.cc index 18e3d19a2..eec5c5e12 100644 --- a/src/model/contact_mechanics/resolutions/resolution_penalty.cc +++ b/src/model/contact_mechanics/resolutions/resolution_penalty.cc @@ -1,154 +1,180 @@ /** * @file resolution_penalty.cc * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Mon Jan 7 2019 * @date last modification: Mon Jan 7 2019 * * @brief Specialization of the resolution class for the penalty method * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "resolution_penalty.hh" namespace akantu { /* -------------------------------------------------------------------------- */ ResolutionPenalty::ResolutionPenalty(ContactMechanicsModel & model, const ID & id) : Resolution(model, id) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::initialize() { this->registerParam("epsilon", epsilon, Real(0.), _pat_parsable | _pat_modifiable, "Normal penalty parameter"); this->registerParam("epsilon_t", epsilon_t, Real(0.), _pat_parsable | _pat_modifiable, "Tangential penalty parameter"); } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeNormalForce(Vector<Real> & force, Vector<Real> & n, Real & gap) { force.clear(); Real tn = gap * epsilon; tn = macaulay(tn); for (UInt i : arange(force.size())) { force[i] += tn * n[i]; } } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeFrictionForce(Vector<Real> & force, Array<Real> & d_alpha, Real & gap) { Vector<Real> tractions(d_alpha.getNbComponent()); - computeFrictionalTraction(tractions); + /*computeFrictionalTraction(tractions); for (auto && values: zip(tractions, make_view(d_alpha, d_alpha.size()))) { auto & t_s = std::get<0>(values); auto & d_s = std::get<1>(values); force += d_s * t_s; - } + }*/ } +/* -------------------------------------------------------------------------- */ +void ResolutionPenalty::computeFrictionTraction(Real & gap) { + + Real tn = gap * epsilon; + tn = macaulay(tn); + + // delta_xi = xi- previous_xi + //trial_traction = previous_traction + epsilon * metric_tensor * delta_xi; + //trial_slip_function = trial_traction.mod - mu * tn; + + // Stick condition + // if trial_slip_function <= 0 + // traction = trial_traction; + + // Slip condition + // else + // traction = mu * tn * trial_traction / trial_traction.norm()' + + +} + /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeTangentModuli(Matrix<Real> & kc, Vector<Real> & n, Array<Real> & n_alpha, Array<Real> & d_alpha, Matrix<Real> & surface_matrix, Real & gap) { computeNormalStiffness(kc, n, n_alpha, d_alpha, surface_matrix, gap); computeFrictionalStiffness(n, n_alpha, d_alpha, gap); } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeNormalStiffness(Matrix<Real> & ke, Vector<Real> & n, Array<Real> & n_alpha, Array<Real> & d_alpha, Matrix<Real> & surface_matrix, Real & gap) { Real tn = gap * epsilon; tn = macaulay(tn); Matrix<Real> n_mat(n.storage(), n.size(), 1); ke.mul<false, true>(n_mat, n_mat); ke *= epsilon * heaviside(gap); for (auto && values: zip(make_view(n_alpha, n_alpha.size()), make_view(d_alpha, d_alpha.size()))) { auto & n_s = std::get<0>(values); auto & d_s = std::get<1>(values); Matrix<Real> ns_mat(n_s.storage(), n_s.size(), 1); Matrix<Real> ds_mat(d_s.storage(), d_s.size(), 1); Matrix<Real> tmp1(n_s.size(), n_s.size()); tmp1.mul<false, true>(ns_mat, ds_mat); Matrix<Real> tmp2(n_s.size(), n_s.size()); tmp1.mul<false, true>(ds_mat, ns_mat); ke -= (tmp1 + tmp2) * tn; } } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeFrictionalStiffness(Vector<Real> & n, Array<Real> & n_alpha, Array<Real> & d_alpha, Real & gap) { - + + computeCommonModuli(); + computeStickModuli(); + computeSlipModuli(); } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeCommonModuli(Real & gap) { } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeStickModuli() { + // epsilon_t * + } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeSlipModuli() { } INSTANTIATE_RESOLUTION(penalty, ResolutionPenalty); } // akantu diff --git a/src/model/contact_mechanics/resolutions/resolution_penalty.hh b/src/model/contact_mechanics/resolutions/resolution_penalty.hh index 21031c0f5..2650e63c0 100644 --- a/src/model/contact_mechanics/resolutions/resolution_penalty.hh +++ b/src/model/contact_mechanics/resolutions/resolution_penalty.hh @@ -1,113 +1,116 @@ /** * @file contact_resolution_penalty.hh * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Mon Jan 29 2018 * * @brief Material isotropic thermo-elastic * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "resolution.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_RESOLUTION_PENALTY_HH__ #define __AKANTU_RESOLUTION_PENALTY_HH__ namespace akantu { class ResolutionPenalty : public Resolution { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ResolutionPenalty(ContactMechanicsModel & model, const ID & id = ""); ~ResolutionPenalty() override = default; protected: /// initialize the resolution void initialize(); /// local computation of stifnness matrix due to normal stress void computeNormalStiffness(Matrix<Real> & kc, Vector<Real> & n, Array<Real> & n_alpha, Array<Real> & d_alpha, Matrix<Real> & surface_matrix, Real & gap); /// local computation of stiffness matrix due to frictional stress void computeFrictionalStiffness(Vector<Real> & n, Array<Real> & n_alpha, Array<Real> & d_alpha, Real & gap); /// local computation of direct stiffness matrix due to friction, /// this matrix is common for both stick and slip part void computeCommonModuli(Real & gap); /// local computaion of stiffness matrix due to stick state void computeStickModuli(); /// local computation of stiffness matrix due to slip state void computeSlipModuli(); + + /// + void computeFrictionalTraction(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// local computation of tangent moduli void computeTangentModuli(Matrix<Real> &, Vector<Real> & /* N */, Array<Real> & /* N_alpha */, Array<Real> & /* D_alpha */, Matrix<Real> & /* A matrix */, Real & /* gap */ ) override; /// local computation of normal force void computeNormalForce(Vector<Real> & /* force vector */, Vector<Real> & /* n */, Real & /* gap */) override; /// local computation of friction force void computeFrictionForce(Vector<Real> & /* force vector */, Array<Real> & /* D_alpha */, Real & /* gap */) override; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// penalty parameter for normal stress Real epsilon; /// penalty parameter for tangential stress Real epsilon_t; }; } // akantu #endif /* __AKANTU_RESOLUTION_PENALTY_HH__ */ diff --git a/src/model/model_couplers/coupler_solid_contact.cc b/src/model/model_couplers/coupler_solid_contact.cc index 7aba79ba4..f6e63cbd2 100644 --- a/src/model/model_couplers/coupler_solid_contact.cc +++ b/src/model/model_couplers/coupler_solid_contact.cc @@ -1,282 +1,415 @@ /** * @file coupler_solid_contact_explicit.cc * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Thu Jan 17 2019 * @date last modification: Thu Jan 17 2019 * * @brief class for coupling of solid mechanics and conatct mechanics * model in explicit * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "coupler_solid_contact.hh" #include "dumpable_inline_impl.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { -CouplerSolidContact::CouplerSolidContact(SolidMechanicsModel & solid, - ContactMechanicsModel & contact, - UInt dim, const ID & id, +CouplerSolidContact::CouplerSolidContact(Mesh & mesh, UInt dim, const ID & id, std::shared_ptr<DOFManager> dof_manager, const ModelType model_type) - : Model(solid.getMesh(), model_type, dof_manager, dim, id), solid(solid), - contact(contact) { + : Model(mesh, model_type, dof_manager, dim, id) { AKANTU_DEBUG_IN(); this->registerFEEngineObject<MyFEEngineType>( - "CouplerSolidContact", solid.getMesh(), Model::spatial_dimension); + "CouplerSolidContact", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("coupler_solid_contact", id, true); - this->mesh.addDumpMeshToDumper("coupler_solid_contact", solid.getMesh(), + this->mesh.addDumpMeshToDumper("coupler_solid_contact", mesh, Model::spatial_dimension, _not_ghost, _ek_regular); #endif this->registerDataAccessor(*this); + + solid = new SolidMechanicsModel(mesh, Model::spatial_dimension, + "solid_mechanics_model", + 0, + this->dof_manager); + contact = new ContactMechanicsModel(mesh, Model::spatial_dimension, + "contact_mechanics_model", + 0, + this->dof_manager); + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ CouplerSolidContact::~CouplerSolidContact() {} /* -------------------------------------------------------------------------- */ void CouplerSolidContact::initFullImpl(const ModelOptions & options) { Model::initFullImpl(options); this->initBC(*this, *displacement, *displacement_increment, *external_force); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::initModel() { + getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); + } /* -------------------------------------------------------------------------- */ FEEngine & CouplerSolidContact::getFEEngineBoundary(const ID & name) { return dynamic_cast<FEEngine &>( getFEEngineClassBoundary<MyFEEngineType>(name)); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::initSolver(TimeStepSolverType, NonLinearSolverType) { DOFManager & dof_manager = this->getDOFManager(); - this->allocNodalField(this->displacement, spatial_dimension, "displacement"); + /*this->allocNodalField(this->displacement, spatial_dimension, "displacement"); this->allocNodalField(this->displacement_increment, spatial_dimension, - "displacement_increment"); + "displacement_increment"); this->allocNodalField(this->external_force, spatial_dimension, "external_force"); if (not dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal); - } + }*/ } /* -------------------------------------------------------------------------- */ std::tuple<ID, TimeStepSolverType> CouplerSolidContact::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_contact: { return std::make_tuple("explicit_contact", _tsst_dynamic); } case _implicit_contact: { return std::make_tuple("implicit_contact", _tsst_static); } default: return std::make_tuple("unkown", _tsst_not_defined); } } /* -------------------------------------------------------------------------- */ ModelSolverOptions CouplerSolidContact::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_dynamic: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } case _tsst_static: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); break; } return options; } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleResidual() { - solid.assembleInternalForces(); - contact.assembleInternalForces(); - this->coupleExternalForces(); + solid->assembleInternalForces(); + contact->assembleInternalForces(); + + auto & contact_force = contact->getInternalForce(); + auto & external_force = solid->getExternalForce(); + auto & internal_force = solid->getInternalForce(); + + /*auto & blocked_dofs = solid->getBlockedDOFs(); + + for (auto && values : zip(make_view(external_force), + make_view(contact_force), + make_view(blocked_dofs))) { + auto & f_ext = std::get<0>(values); + auto & f_con = std::get<1>(values); + auto & blocked = std::get<2>(values); + + if (!blocked) + f_ext = f_con; + }*/ + + + /* ------------------------------------------------------------------------ */ + this->getDOFManager().assembleToResidual("displacement", + external_force, 1); + this->getDOFManager().assembleToResidual("displacement", + internal_force, 1); + this->getDOFManager().assembleToResidual("displacement", + contact_force, 1); } /* -------------------------------------------------------------------------- */ -void CouplerSolidContact::beforeSolveStep() { contact.search(); } +void CouplerSolidContact::beforeSolveStep() { + contact->search(); +} /* -------------------------------------------------------------------------- */ void CouplerSolidContact::afterSolveStep() {} /* -------------------------------------------------------------------------- */ MatrixType CouplerSolidContact::getMatrixType(const ID & matrix_id) { if (matrix_id == "K") return _symmetric; return _mt_not_defined; } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleMatrix(const ID & matrix_id) { - if (matrix_id == "K") - contact.assembleStiffnessMatrix(); + if (matrix_id == "K") { + solid->assembleStiffnessMatrix(); + contact->assembleStiffnessMatrix(); + } - //auto & solid_tss = solid.getTimeStepSolver(); - // solid.assembleMatrix(matrix_id); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleLumpedMatrix(const ID & /*matrix_id*/) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::coupleExternalForces() { - auto & contact_force = contact.getInternalForce(); - auto & external_force = solid.getExternalForce(); - auto & blocked_dofs = solid.getBlockedDOFs(); + auto & contact_force = contact->getInternalForce(); + auto & external_force = solid->getExternalForce(); + auto & blocked_dofs = solid->getBlockedDOFs(); for (auto && values : zip(make_view(external_force), make_view(contact_force), make_view(blocked_dofs))) { auto & f_ext = std::get<0>(values); auto & f_con = std::get<1>(values); auto & blocked = std::get<2>(values); if (!blocked) f_ext = f_con; } } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::coupleStiffnessMatrices() { auto & contact_stiffness = - const_cast<SparseMatrix &>(contact.getDOFManager().getMatrix("K")); + const_cast<SparseMatrix &>(contact->getDOFManager().getMatrix("K")); auto & solid_stiffness = - const_cast<SparseMatrix &>(solid.getDOFManager().getMatrix("K")); + const_cast<SparseMatrix &>(solid->getDOFManager().getMatrix("K")); solid_stiffness.add(contact_stiffness); } /* -------------------------------------------------------------------------- */ // void CouplerSolidContact::solve() { // search for contacts // contact.search(); // can be handled by beforeSolveStep() /// assemble contact forces /// contact.assembleInternalForces(); /// assemble contact stiffness matrix /// contact.assembleStiffnessMatrix(); /// can be handled by solveStep but no need to solve it /// couple the external forces // this->coupleExternalForces(); // assemble the internal forces solid mechanics model // assemble the stiffness forces // couple the contact mechanics model stiffness to solid mechanics // this->coupleStiffnessMatrices(); // and solve the solid mechanics model with new stifffness anf // residual /// all the above steps for solid mehcanics should be handled by the // solveStep method with solvercall back to see that stifffness // matrices are coupled // ContactSolver callback(solid, contact); // contact.solveStep(); // solid.solveStep(callback); //} /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER +/* -------------------------------------------------------------------------- */ +dumper::Field * CouplerSolidContact::createElementalField( + const std::string & field_name, const std::string & group_name, + bool padding_flag, const UInt & spatial_dimension, + const ElementKind & kind) { + + dumper::Field * field = nullptr; + + field = solid->createElementalField(field_name, group_name, padding_flag, + spatial_dimension, kind); + + return field; +} + + + /* -------------------------------------------------------------------------- */ dumper::Field * CouplerSolidContact::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { - std::map<std::string, Array<Real> *> real_nodal_fields; - real_nodal_fields["displacement"] = this->displacement; - real_nodal_fields["external_force"] = this->external_force; - dumper::Field * field = nullptr; - if (padding_flag) - field = this->mesh.createNodalField(real_nodal_fields[field_name], - group_name, 3); - else - field = - this->mesh.createNodalField(real_nodal_fields[field_name], group_name); + + field = solid->createNodalFieldReal(field_name, group_name, padding_flag); return field; } +/* -------------------------------------------------------------------------- */ +dumper::Field * CouplerSolidContact::createNodalFieldBool( + const std::string & field_name, const std::string & group_name, + __attribute__((unused)) bool padding_flag) { + + dumper::Field * field = nullptr; + field = solid->createNodalFieldBool(field_name, group_name, padding_flag); + return field; +} + #else + /* -------------------------------------------------------------------------- */ -dumper::Field * CouplerSolidContact::createNodalFieldReal( - __attribute__((unused)) const std::string & field_name, - __attribute__((unused)) const std::string & group_name, - __attribute__((unused)) bool padding_flag) { +dumper::Field * CouplerSolidContact::createElementalField(const std::string &, + const std::string &, + bool, const UInt &, + const ElementKind &) { + return nullptr; +} +/* ----------------------------------------------------------------------- */ +dumper::Field * CouplerSolidContact::createNodalFieldReal(const std::string &, + const std::string &, + bool) { return nullptr; } +/*-------------------------------------------------------------------*/ +dumper::Field * CouplerSolidContact::createNodalFieldBool(const std::string &, + const std::string &, + bool) { + return nullptr; +} + #endif +/* -------------------------------------------------------------------------- */ +UInt CouplerSolidContact::getNbData( + const Array<Element> & elements, const SynchronizationTag & /*tag*/) const { + AKANTU_DEBUG_IN(); + + UInt size = 0; + UInt nb_nodes_per_element = 0; + + for (const Element & el : elements) { + nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); + } + + AKANTU_DEBUG_OUT(); + return size; +} + +/* -------------------------------------------------------------------------- */ +void CouplerSolidContact::packData(CommunicationBuffer & /*buffer*/, + const Array<Element> & /*elements*/, + const SynchronizationTag & /*tag*/) const { + AKANTU_DEBUG_IN(); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CouplerSolidContact::unpackData(CommunicationBuffer & /*buffer*/, + const Array<Element> & /*elements*/, + const SynchronizationTag & /*tag*/) { + AKANTU_DEBUG_IN(); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +UInt CouplerSolidContact::getNbData( + const Array<UInt> & dofs, const SynchronizationTag & /*tag*/) const { + AKANTU_DEBUG_IN(); + + UInt size = 0; + // UInt nb_nodes = mesh.getNbNodes(); + + AKANTU_DEBUG_OUT(); + return size * dofs.size(); +} + +/* -------------------------------------------------------------------------- */ +void CouplerSolidContact::packData(CommunicationBuffer & /*buffer*/, + const Array<UInt> & /*dofs*/, + const SynchronizationTag & /*tag*/) const { + AKANTU_DEBUG_IN(); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CouplerSolidContact::unpackData(CommunicationBuffer & /*buffer*/, + const Array<UInt> & /*dofs*/, + const SynchronizationTag & /*tag*/) { + AKANTU_DEBUG_IN(); + + AKANTU_DEBUG_OUT(); +} + + } // namespace akantu diff --git a/src/model/model_couplers/coupler_solid_contact.hh b/src/model/model_couplers/coupler_solid_contact.hh index e2c13107e..fa16f370c 100644 --- a/src/model/model_couplers/coupler_solid_contact.hh +++ b/src/model/model_couplers/coupler_solid_contact.hh @@ -1,189 +1,228 @@ /** * @file coupler_solid_contact_explicit.hh * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Thu Jan 17 2019 * @date last modification: Thu Jan 17 2019 * * @brief class for coupling of solid mechanics and conatct mechanics * model in explicit * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "contact_mechanics_model.hh" #include "data_accessor.hh" #include "model.hh" #include "solid_mechanics_model.hh" #include "sparse_matrix.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COUPLER_SOLID_CONTACT_HH__ #define __AKANTU_COUPLER_SOLID_CONTACT_HH__ /* ------------------------------------------------------------------------ */ /* Coupling : Solid Mechanics / Contact Mechanics */ /* ------------------------------------------------------------------------ */ namespace akantu { template <ElementKind kind, class IntegrationOrderFunctor> class IntegratorGauss; template <ElementKind kind> class ShapeLagrange; class DOFManager; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ class CouplerSolidContact : public Model, public DataAccessor<Element>, public DataAccessor<UInt>, public BoundaryCondition<CouplerSolidContact> { /* ------------------------------------------------------------------------ */ /* Constructor/Destructor */ /* ------------------------------------------------------------------------ */ using MyFEEngineType = FEEngineTemplate<IntegratorGauss, ShapeLagrange>; public: - CouplerSolidContact( - SolidMechanicsModel &, ContactMechanicsModel &, + CouplerSolidContact(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "coupler_solid_contact", std::shared_ptr<DOFManager> dof_manager = nullptr, const ModelType model_type = ModelType::_coupler_solid_contact); ~CouplerSolidContact() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize completely the model void initFullImpl(const ModelOptions & options) override; /// allocate all vectors void initSolver(TimeStepSolverType, NonLinearSolverType) override; /// initialize the modelType void initModel() override; /// call back for the solver, computes the force residual void assembleResidual() override; /// get the type of matrix needed MatrixType getMatrixType(const ID & matrix_id) override; /// callback for the solver, this assembles different matrices void assembleMatrix(const ID & matrix_id) override; /// callback for the solver, this assembles the stiffness matrix void assembleLumpedMatrix(const ID & matrix_id) override; /// get some default values for derived classes std::tuple<ID, TimeStepSolverType> getDefaultSolverID(const AnalysisMethod & method) override; ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const; /// callback for the solver, this is called at beginning of solve void beforeSolveStep() override; /// callback for the solver, this is called at end of solve void afterSolveStep() override; + /* ------------------------------------------------------------------------ */ + /* Data Accessor inherited members */ + /* ------------------------------------------------------------------------ */ +public: + UInt getNbData(const Array<Element> & elements, + const SynchronizationTag & tag) const override; + + void packData(CommunicationBuffer & buffer, const Array<Element> & elements, + const SynchronizationTag & tag) const override; + + void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, + const SynchronizationTag & tag) override; + + UInt getNbData(const Array<UInt> & dofs, + const SynchronizationTag & tag) const override; + + void packData(CommunicationBuffer & buffer, const Array<UInt> & dofs, + const SynchronizationTag & tag) const override; + + void unpackData(CommunicationBuffer & buffer, const Array<UInt> & dofs, + const SynchronizationTag & tag) override; + + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: FEEngine & getFEEngineBoundary(const ID & name = "") override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt); /// get the ContactMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array<Real> &); /// get the ContactMechanicsModel::increment vector \warn only consistent /// if ContactMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *displacement_increment, Array<Real> &); /// get the ContactMechanicsModel::external_force vector (external forces) AKANTU_GET_MACRO(ExternalForce, *external_force, Array<Real> &); /// get the ContactMechanicsModel::force vector (external forces) Array<Real> & getForce() { AKANTU_DEBUG_WARNING("getForce was maintained for backward compatibility, " "use getExternalForce instead"); return *external_force; } + /// get the solid mechanics model + AKANTU_GET_MACRO(SolidMechanicsModel, *solid, SolidMechanicsModel &); + + /// get the contact mechanics model + AKANTU_GET_MACRO(ContactMechanicsModel, *contact, ContactMechanicsModel &); + /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: + dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) override; + dumper::Field * createNodalFieldBool(const std::string & field_name, + const std::string & group_name, + bool padding_flag) override; + + dumper::Field * createElementalField(const std::string & field_name, + const std::string & group_name, + bool padding_flag, + const UInt & spatial_dimension, + const ElementKind & kind) override; + /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ private: /// couples external forces between models void coupleExternalForces(); /// couples stiffness matrices between models void coupleStiffnessMatrices(); /* ------------------------------------------------------------------------ */ /* Members */ /* ------------------------------------------------------------------------ */ private: /// solid mechanics model - SolidMechanicsModel & solid; + SolidMechanicsModel * solid{nullptr}; /// contact mechanics model - ContactMechanicsModel & contact; + ContactMechanicsModel * contact{nullptr}; - /// displacements array + /// Array<Real> * displacement{nullptr}; - /// increment of displacement + /// Array<Real> * displacement_increment{nullptr}; - + /// external forces array Array<Real> * external_force{nullptr}; }; } // namespace akantu #endif /* __COUPLER_SOLID_CONTACT_HH__ */ diff --git a/src/model/model_solver.hh b/src/model/model_solver.hh index 52724261b..410623aaa 100644 --- a/src/model/model_solver.hh +++ b/src/model/model_solver.hh @@ -1,201 +1,201 @@ /** * @file model_solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Wed Jan 31 2018 * * @brief Class regrouping the common solve interface to the different models * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "integration_scheme.hh" #include "parsable.hh" #include "solver_callback.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MODEL_SOLVER_HH__ #define __AKANTU_MODEL_SOLVER_HH__ namespace akantu { class Mesh; class DOFManager; class TimeStepSolver; class NonLinearSolver; struct ModelSolverOptions; } namespace akantu { class ModelSolver : public Parsable, public SolverCallback, public SynchronizerRegistry { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ModelSolver(Mesh & mesh, const ModelType & type, const ID & id, - UInt memory_id, std::shared_ptr<DOFManager> dof_manager); + UInt memory_id, std::shared_ptr<DOFManager> dof_manager=nullptr); ~ModelSolver() override; /// initialize the dof manager based on solver type passed in the input file void initDOFManager(); /// initialize the dof manager based on the used chosen solver type void initDOFManager(const ID & solver_type); protected: /// initialize the dof manager based on the used chosen solver type void initDOFManager(const ParserSection & section, const ID & solver_type); /// Callback for the model to instantiate the matricees when needed virtual void initSolver(TimeStepSolverType /*time_step_solver_type*/, NonLinearSolverType /*non_linear_solver_type*/) {} /// get the section in the input file (if it exsits) corresponding to this /// model std::tuple<ParserSection, bool> getParserSection(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// solve a step using a given pre instantiated time step solver and /// non linear solver virtual void solveStep(const ID & solver_id = ""); /// solve a step using a given pre instantiated time step solver and /// non linear solver with a user defined callback instead of the /// model itself /!\ This can mess up everything virtual void solveStep(SolverCallback & callback, const ID & solver_id = ""); /// Initialize a time solver that can be used afterwards with its id void getNewSolver(const ID & solver_id, TimeStepSolverType time_step_solver_type, NonLinearSolverType non_linear_solver_type = _nls_auto); /// set an integration scheme for a given dof and a given solver void setIntegrationScheme(const ID & solver_id, const ID & dof_id, const IntegrationSchemeType & integration_scheme_type, IntegrationScheme::SolutionType solution_type = IntegrationScheme::_not_defined); /// set an externally instantiated integration scheme void setIntegrationScheme(const ID & solver_id, const ID & dof_id, IntegrationScheme & integration_scheme, IntegrationScheme::SolutionType solution_type = IntegrationScheme::_not_defined); /* ------------------------------------------------------------------------ */ /* SolverCallback interface */ /* ------------------------------------------------------------------------ */ public: /// Predictor interface for the callback void predictor() override; /// Corrector interface for the callback void corrector() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Default time step solver to instantiate for this model virtual TimeStepSolverType getDefaultSolverType() const; /// Default configurations for a given time step solver virtual ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const; /// get access to the internal dof manager DOFManager & getDOFManager() { return *this->dof_manager; } /// get the time step of a given solver Real getTimeStep(const ID & solver_id = "") const; /// set the time step of a given solver virtual void setTimeStep(Real time_step, const ID & solver_id = ""); /// set the parameter 'param' of the solver 'solver_id' // template <typename T> // void set(const ID & param, const T & value, const ID & solver_id = ""); /// get the parameter 'param' of the solver 'solver_id' // const Parameter & get(const ID & param, const ID & solver_id = "") const; /// answer to the question "does the solver exists ?" bool hasSolver(const ID & solver_id) const; /// changes the current default solver void setDefaultSolver(const ID & solver_id); /// is a default solver defined bool hasDefaultSolver() const; /// is an integration scheme set for a given solver and a given dof bool hasIntegrationScheme(const ID & solver_id, const ID & dof_id) const; TimeStepSolver & getTimeStepSolver(const ID & solver_id = ""); NonLinearSolver & getNonLinearSolver(const ID & solver_id = ""); const TimeStepSolver & getTimeStepSolver(const ID & solver_id = "") const; const NonLinearSolver & getNonLinearSolver(const ID & solver_id = "") const; private: TimeStepSolver & getSolver(const ID & solver_id); const TimeStepSolver & getSolver(const ID & solver_id) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: ModelType model_type; /// Underlying dof_manager (the brain...) std::shared_ptr<DOFManager> dof_manager; private: ID parent_id; UInt parent_memory_id; /// Underlying mesh Mesh & mesh; /// Default time step solver to use ID default_solver_id{""}; }; struct ModelSolverOptions { NonLinearSolverType non_linear_solver_type; std::map<ID, IntegrationSchemeType> integration_scheme_type; std::map<ID, IntegrationScheme::SolutionType> solution_type; }; } // akantu #endif /* __AKANTU_MODEL_SOLVER_HH__ */ diff --git a/test/test_model/test_contact_mechanics_model/test_coupler/test_contact_coupling.cc b/test/test_model/test_contact_mechanics_model/test_coupler/test_contact_coupling.cc index 7e859ad0d..f6b5938c9 100644 --- a/test/test_model/test_contact_mechanics_model/test_coupler/test_contact_coupling.cc +++ b/test/test_model/test_contact_mechanics_model/test_coupler/test_contact_coupling.cc @@ -1,70 +1,76 @@ /** * @file test_contact_coupler.cc * * @author Mohit Pundir <mohit.pundir@epfl.ch> * * @date creation: Tue Apr 30 2019 * @date last modification: Tue Apr 30 2019 * * @brief Test for contact mechanics model class * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "coupler_solid_contact.hh" -#include "non_linear_solver.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { const UInt spatial_dimension = 2; initialize("material.dat", argc, argv); Mesh mesh(spatial_dimension); mesh.read("coupling.msh"); - SolidMechanicsModel solid(mesh); + CouplerSolidContact coupler(mesh); + + auto & solid = coupler.getSolidMechanicsModel(); + auto & contact = coupler.getContactMechanicsModel(); + solid.initFull(_analysis_method = _static); + contact.initFull(_analysis_method = _implicit_contact); solid.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "bot_body"); solid.applyBC(BC::Dirichlet::IncrementValue(0.001, _y), "bot_body"); solid.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "top"); solid.applyBC(BC::Dirichlet::FixedValue(0.0, _y), "top"); - - auto & solver = solid.getNonLinearSolver(); - solver.set("max_iterations", 1); - solver.set("threshold", 1e-1); - solver.set("convergence_type", _scc_solution); - ContactMechanicsModel contact(mesh); - contact.initFull(_analysis_method = _implicit_contact); - - CouplerSolidContact coupler(solid, contact); coupler.initFull(_analysis_method = _implicit_contact); + + coupler.setBaseName("coupling"); + coupler.addDumpFieldVector("displacement"); + coupler.addDumpField("blocked_dofs"); + coupler.addDumpField("external_force"); + coupler.addDumpField("internal_force"); + coupler.addDumpField("grad_u"); + coupler.addDumpField("stress"); + coupler.solveStep(); + contact.dump(); + return 0; }