diff --git a/cmake/Modules/CMakeVersionGenerator.cmake b/cmake/Modules/CMakeVersionGenerator.cmake index d95bee5ce..1f37c8ad6 100644 --- a/cmake/Modules/CMakeVersionGenerator.cmake +++ b/cmake/Modules/CMakeVersionGenerator.cmake @@ -1,250 +1,250 @@ #=============================================================================== # @file CMakeVersionGenerator.cmake # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Sun Oct 19 2014 # @date last modification: Mon Jan 18 2016 # # @brief Set of macros used by akantu to handle the package system # # # @section LICENSE # # Copyright (©) 2015-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License along # with Akantu. If not, see . # #=============================================================================== if(__DEFINE_PROJECT_VERSION__) return() endif() set(__DEFINE_PROJECT_VERSION__ TRUE) function(_match_semver _input_semver prefix) set(_semver_regexp "^([0-9]+(\\.[0-9]+)?(\\.[0-9]+)?)(-([a-zA-Z0-9\-]*))?(\\+(.*))?") if(_input_semver MATCHES "^([0-9]+(\\.[0-9]+)?(\\.[0-9]+)?)(-([a-zA-Z0-9-]*))?(\\+(.*))?") set(${prefix}_version ${CMAKE_MATCH_1} PARENT_SCOPE) if(CMAKE_MATCH_4) set(${prefix}_version_prerelease "${CMAKE_MATCH_5}" PARENT_SCOPE) endif() if(CMAKE_MATCH_6) set(${prefix}_version_metadata "${CMAKE_MATCH_7}" PARENT_SCOPE) endif() endif() endfunction() function(_get_version_from_git) if(NOT CMAKE_VERSION_GENERATOR_TAG_PREFIX) set(CMAKE_VERSION_GENERATOR_TAG_PREFIX "v") endif() find_package(Git) if(NOT Git_FOUND) return() endif() execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 --match ${CMAKE_VERSION_GENERATOR_TAG_PREFIX}* WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE _res OUTPUT_VARIABLE _out_tag OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE _err_tag) if(NOT _res EQUAL 0) return() endif() string(REGEX REPLACE "^${CMAKE_VERSION_GENERATOR_TAG_PREFIX}(.*)" "\\1" _tag "${_out_tag}") _match_semver("${_tag}" _tag) execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --dirty --always --long --match ${CMAKE_VERSION_GENERATOR_TAG_PREFIX}* WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE _res OUTPUT_VARIABLE _out OUTPUT_STRIP_TRAILING_WHITESPACE) set(_git_version ${_tag_version} PARENT_SCOPE) if(_tag_version_prerelease) set(_git_version_prerelease ${_tag_version_prerelease} PARENT_SCOPE) endif() # git describe to PEP404 version set(_version_regex "^${CMAKE_VERSION_GENERATOR_TAG_PREFIX}${_tag}(-([0-9]+)-(g[0-9a-f]+)(-dirty)?)?$") if(_out MATCHES ${_version_regex}) if(CMAKE_MATCH_1) if(_tag_version_metadata) set(_metadata "${_tag_version_metadata}.") endif() set(_metadata "${_metadata}${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") endif() if(CMAKE_MATCH_4) set(_metadata "${_metadata}.dirty") endif() else() execute_process( COMMAND ${GIT_EXECUTABLE} rev-list HEAD --count WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE _res OUTPUT_VARIABLE _out_count OUTPUT_STRIP_TRAILING_WHITESPACE) if(_out MATCHES "^([0-9a-f]+)(-dirty)?$") set(_metadata "${CMAKE_MATCH_1}") if(_res EQUAL 0) set(_metadata "${_out_count}.${_metadata}") endif() if(CMAKE_MATCH_2) set(_metadata "${_metadata}.dirty") endif() endif() endif() set(_git_version_metadata ${_metadata} PARENT_SCOPE) endfunction() function(_get_version_from_file) if(EXISTS ${PROJECT_SOURCE_DIR}/VERSION) file(STRINGS ${PROJECT_SOURCE_DIR}/VERSION _file_version) _match_semver("${_file_version}" "_file") set(_file_version ${_file_version} PARENT_SCOPE) if(_file_version_metadata) set(_file_version_metadata ${_file_version_metadata} PARENT_SCOPE) endif() if(_file_version_prerelease) set(_file_version_prerelease ${_file_version_prerelease} PARENT_SCOPE) endif() endif() endfunction() function(_get_metadata_from_ci) if(NOT DEFINED ENV{CI}) return() endif() if(DEFINED ENV{CI_MERGE_REQUEST_ID}) set(_ci_version_metadata "ci.mr$ENV{CI_MERGE_REQUEST_ID}" PARENT_SCOPE) endif() endfunction() function(define_project_version) string(TOUPPER ${PROJECT_NAME} _project) _get_version_from_git() if(_git_version) set(_version "${_git_version}") if(_git_version_metadata) set(_version_metadata "${_git_version_metadata}") endif() if (_git_version_prerelease) set(_version_prerelease "${_git_version_prerelease}") endif() else() # we can get metadata if and no version if not tag is properly defined if(_git_version_metadata) set(git_version_metadata ".${_git_version_metadata}") endif() _get_version_from_file() if(_file_version_metadata) set(_version_metadata "${_version_metadata}${_git_version_metadata}") endif() if (_file_version) set(_version "${_file_version}") endif() if (_file_version_prerelease) set(_version_prerelease "${_file_version_prerelease}") endif() endif() _get_metadata_from_ci() if(_version) if(_version_prerelease) set(_version_prerelease "-${_version_prerelease}") endif() if(_version_metadata) set(_version_metadata "+${_version_metadata}") if(_ci_version_metadata) set(_version_metadata "${_version_metadata}.${_ci_version_metadata}") endif() endif() set(${_project}_VERSION ${_version} PARENT_SCOPE) set(_semver "${_version}${_version_prerelease}${_version_metadata}") set(${_project}_SEMVER "${_semver}" PARENT_SCOPE) message(STATUS "${PROJECT_NAME} version: ${_semver}") if(_version MATCHES "^([0-9]+)(\\.([0-9]+))?(\\.([0-9]+))?") set(_major_version ${CMAKE_MATCH_1}) set(${_project}_MAJOR_VERSION ${_major_version} PARENT_SCOPE) if(CMAKE_MATCH_2) set(_minor_version ${CMAKE_MATCH_3}) set(${_project}_MINOR_VERSION ${_minor_version} PARENT_SCOPE) endif() if(CMAKE_MATCH_4) set(_patch_version ${CMAKE_MATCH_5}) set(${_project}_PATCH_VERSION ${_patch_version} PARENT_SCOPE) endif() if(_version_prerelease) set(${_project}_PRERELEASE_VERSION ${_version_prerelease} PARENT_SCOPE) endif() if(_version_metadata) set(${_project}_LOCAL_VERSION ${_version_metadata} PARENT_SCOPE) endif() if(_version_metadata MATCHES "(\\+([0-9]+))(\\..*)*") set(${_project}_TWEAK ${CMAKE_MATCH_1} PARENT_SCOPE) endif() endif() else() message(FATAL_ERROR "Could not determine the VERSION for ${PROJECT_NAME}") endif() if(NOT ${_project}_NO_LIBRARY_VERSION) set(${_project}_LIBRARY_PROPERTIES ${${_project}_LIBRARY_PROPERTIES} VERSION "${_version}" SOVERSION "${_major_version}.${_minor_version}" - ) + PARENT_SCOPE) endif() endfunction() diff --git a/extra_packages/traction-at-split-node-contact/src/common/manual_restart.cc b/extra_packages/traction-at-split-node-contact/src/common/manual_restart.cc index de3631671..c3985d894 100644 --- a/extra_packages/traction-at-split-node-contact/src/common/manual_restart.cc +++ b/extra_packages/traction-at-split-node-contact/src/common/manual_restart.cc @@ -1,136 +1,136 @@ /** * @file manual_restart.cc * * @author Dana Christen * * @date creation: Fri Mar 16 2018 * @date last modification: Fri Mar 16 2018 * * @brief Tools to do a restart * * * @section LICENSE * * Copyright (©) 2015-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "manual_restart.hh" #include "dof_manager_default.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ using namespace akantu; void dumpArray(const Array & array, const std::string & fname) { std::ofstream outFile; outFile.open(fname.c_str()); outFile.precision(9); outFile.setf(std::ios::scientific); auto size = array.size(); auto nb_component = array.getNbComponent(); outFile << size << std::endl; outFile << nb_component << std::endl; for (auto && v : make_view(array, nb_component)) { - for (UInt c = 0; c < nb_component; ++c) { + for (Int c = 0; c < nb_component; ++c) { if (c != 0) { outFile << " "; } outFile << (v)(c); } outFile << std::endl; } outFile.close(); } void loadArray(Array & array, const std::string & fname) { std::ifstream inFile; inFile.open(fname.c_str()); inFile.precision(9); inFile.setf(std::ios::scientific); Int size(0), nb_comp(0); inFile >> size; inFile >> nb_comp; AKANTU_DEBUG_ASSERT(array.getNbComponent() == nb_comp, "BAD NUM OF COMPONENTS"); AKANTU_DEBUG_ASSERT(array.size() == size, "loadArray: number of data points in file (" << size << ") does not correspond to array size (" << array.size() << ")!!"); array.resize(size); for (auto && v : make_view(array, array.getNbComponent())) { for (auto && c : v) { inFile >> c; } } inFile.close(); } /* -------------------------------------------------------------------------- */ void loadRestart(akantu::SolidMechanicsModel & model, const std::string & fname, akantu::UInt prank) { const auto & mesh = model.getMesh(); auto spatial_dimension = model.getMesh().getSpatialDimension(); auto & dof_manager = dynamic_cast(model.getDOFManager()); if (prank == 0) { akantu::Array full_reload_array(mesh.getNbGlobalNodes(), spatial_dimension); loadArray(full_reload_array, fname); dof_manager.getSynchronizer().scatter(model.getDisplacement(), full_reload_array); } else { dof_manager.getSynchronizer().scatter(model.getDisplacement()); } } /* -------------------------------------------------------------------------- */ void loadRestart(akantu::SolidMechanicsModel & model, const std::string & fname) { loadArray(model.getDisplacement(), fname); } /* -------------------------------------------------------------------------- */ void dumpRestart(akantu::SolidMechanicsModel & model, const std::string & fname, akantu::UInt prank) { const akantu::Mesh & mesh = model.getMesh(); const akantu::Int spatial_dimension = model.getMesh().getSpatialDimension(); auto & dof_manager = dynamic_cast(model.getDOFManager()); if (prank == 0) { akantu::Array full_array(mesh.getNbGlobalNodes(), spatial_dimension); dof_manager.getSynchronizer().gather(model.getDisplacement(), full_array); dumpArray(full_array, fname); } else { dof_manager.getSynchronizer().gather(model.getDisplacement()); } } /* -------------------------------------------------------------------------- */ void dumpRestart(akantu::SolidMechanicsModel & model, const std::string & fname) { dumpArray(model.getDisplacement(), fname); } diff --git a/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_contact.cc b/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_contact.cc index 97714bc00..7f9d53dfb 100644 --- a/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_contact.cc +++ b/extra_packages/traction-at-split-node-contact/src/ntn_contact/ntn_base_contact.cc @@ -1,548 +1,548 @@ /** * @file ntn_base_contact.cc * * @author David Simon Kammer * * @date creation: Fri Mar 16 2018 * @date last modification: Tue Sep 29 2020 * * @brief implementation of ntn base contact * * * @section LICENSE * * Copyright (©) 2015-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "ntn_base_contact.hh" #include "dof_manager_default.hh" #include "dumpable_inline_impl.hh" #include "dumper_nodal_field.hh" #include "dumper_text.hh" #include "element_synchronizer.hh" #include "mesh_utils.hh" #include "non_linear_solver_lumped.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ // NTNContactSynchElementFilter::NTNContactSynchElementFilter( // NTNBaseContact & contact) // : contact(contact), // connectivity(contact.getModel().getMesh().getConnectivities()) { // AKANTU_DEBUG_IN(); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ // bool NTNContactSynchElementFilter::operator()(const Element & e) { // AKANTU_DEBUG_IN(); // ElementType type = e.type; // UInt element = e.element; // GhostType ghost_type = e.ghost_type; // // loop over all nodes of this element // bool need_element = false; // UInt nb_nodes = Mesh::getNbNodesPerElement(type); // for (UInt n = 0; n < nb_nodes; ++n) { // UInt nn = this->connectivity(type, ghost_type)(element, n); // // if one nodes is in this contact, we need this element // if (this->contact.getNodeIndex(nn) >= 0) { // need_element = true; // break; // } // } // AKANTU_DEBUG_OUT(); // return need_element; // } /* -------------------------------------------------------------------------- */ NTNBaseContact::NTNBaseContact(SolidMechanicsModel & model, const ID & id) : id(id), model(model), slaves(0, 1, 0, id + ":slaves", std::numeric_limits::quiet_NaN(), "slaves"), normals(0, model.getSpatialDimension(), 0, id + ":normals", std::numeric_limits::quiet_NaN(), "normals"), contact_pressure( 0, model.getSpatialDimension(), 0, id + ":contact_pressure", std::numeric_limits::quiet_NaN(), "contact_pressure"), is_in_contact(0, 1, false, id + ":is_in_contact", false, "is_in_contact"), lumped_boundary_slaves(0, 1, 0, id + ":lumped_boundary_slaves", std::numeric_limits::quiet_NaN(), "lumped_boundary_slaves"), impedance(0, 1, 0, id + ":impedance", std::numeric_limits::quiet_NaN(), "impedance"), slave_elements("slave_elements", id) { AKANTU_DEBUG_IN(); auto & boundary_fem = this->model.getFEEngineBoundary(); for (auto && ghost_type : ghost_types) { boundary_fem.initShapeFunctions(ghost_type); } auto & mesh = this->model.getMesh(); auto spatial_dimension = this->model.getSpatialDimension(); this->slave_elements.initialize(mesh, _spatial_dimension = spatial_dimension - 1); MeshUtils::buildNode2Elements(mesh, this->node_to_elements, spatial_dimension - 1); this->registerDumper("text_all", id, true); this->addDumpFilteredMesh(mesh, slave_elements, slaves.getArray(), spatial_dimension - 1, _not_ghost, _ek_regular); // parallelisation this->synch_registry = std::make_unique(); this->synch_registry->registerDataAccessor(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NTNBaseContact::~NTNBaseContact() = default; /* -------------------------------------------------------------------------- */ void NTNBaseContact::initParallel() { AKANTU_DEBUG_IN(); this->synchronizer = std::make_unique( this->model.getMesh().getElementSynchronizer()); this->synchronizer->filterScheme([&](auto && element) { // loop over all nodes of this element auto && conn = this->model.getMesh().getConnectivity(element); for (auto & node : conn) { // if one nodes is in this contact, we need this element if (this->getNodeIndex(node) >= 0) { return true; } } return false; }); this->synch_registry->registerSynchronizer(*(this->synchronizer), SynchronizationTag::_cf_nodal); this->synch_registry->registerSynchronizer(*(this->synchronizer), SynchronizationTag::_cf_incr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::findBoundaryElements(const Array & interface_nodes, ElementTypeMapArray & elements) { AKANTU_DEBUG_IN(); // add connected boundary elements that have all nodes on this contact for (const auto & node : interface_nodes) { for (const auto & element : this->node_to_elements.getRow(node)) { Vector conn = this->model.getMesh().getConnectivity(element); auto nb_nodes = conn.size(); decltype(nb_nodes) nb_found_nodes = 0; for (auto & nn : conn) { - if (interface_nodes.find(nn) != UInt(-1)) { + if (interface_nodes.find(nn) != -1) { nb_found_nodes++; } else { break; } } // this is an element between all contact nodes // and is not already in the elements if ((nb_found_nodes == nb_nodes) && (elements(element.type, element.ghost_type).find(element.element) == - UInt(-1))) { + -1)) { elements(element.type, element.ghost_type).push_back(element.element); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::addSplitNode(Idx node, Idx /*unused*/) { AKANTU_DEBUG_IN(); Int dim = this->model.getSpatialDimension(); // add to node arrays this->slaves.push_back(node); // set contact as false this->is_in_contact.push_back(false); // before initializing // set contact pressure, normal, lumped_boundary to Nan this->contact_pressure.push_back(std::numeric_limits::quiet_NaN()); this->impedance.push_back(std::numeric_limits::quiet_NaN()); this->lumped_boundary_slaves.push_back( std::numeric_limits::quiet_NaN()); Vector nan_normal(dim); nan_normal.fill(std::numeric_limits::quiet_NaN()); this->normals.push_back(nan_normal); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::registerSynchronizedArray(SynchronizedArrayBase & array) { AKANTU_DEBUG_IN(); this->slaves.registerDependingArray(array); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::dumpRestart(const std::string & file_name) const { AKANTU_DEBUG_IN(); this->slaves.dumpRestartFile(file_name); this->normals.dumpRestartFile(file_name); this->is_in_contact.dumpRestartFile(file_name); this->contact_pressure.dumpRestartFile(file_name); this->lumped_boundary_slaves.dumpRestartFile(file_name); this->impedance.dumpRestartFile(file_name); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::readRestart(const std::string & file_name) { AKANTU_DEBUG_IN(); this->slaves.readRestartFile(file_name); this->normals.readRestartFile(file_name); this->is_in_contact.readRestartFile(file_name); this->contact_pressure.readRestartFile(file_name); this->lumped_boundary_slaves.readRestartFile(file_name); this->impedance.readRestartFile(file_name); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Int NTNBaseContact::getNbNodesInContact() const { AKANTU_DEBUG_IN(); Int nb_contact = 0; auto nb_nodes = this->getNbContactNodes(); const auto & mesh = this->model.getMesh(); for (Int n = 0; n < nb_nodes; ++n) { auto is_local_node = mesh.isLocalOrMasterNode(this->slaves(n)); auto is_pbc_slave_node = mesh.isPeriodicSlave(this->slaves(n)); if (is_local_node && !is_pbc_slave_node && this->is_in_contact(n)) { nb_contact++; } } mesh.getCommunicator().allReduce(nb_contact, SynchronizerOperation::_sum); AKANTU_DEBUG_OUT(); return nb_contact; } /* -------------------------------------------------------------------------- */ void NTNBaseContact::updateInternalData() { AKANTU_DEBUG_IN(); updateNormals(); updateLumpedBoundary(); updateImpedance(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::updateLumpedBoundary() { AKANTU_DEBUG_IN(); this->internalUpdateLumpedBoundary(this->slaves.getArray(), this->slave_elements, this->lumped_boundary_slaves); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::internalUpdateLumpedBoundary( const Array & nodes, const ElementTypeMapArray & elements, SynchronizedArray & boundary) { AKANTU_DEBUG_IN(); // set all values in lumped_boundary to zero boundary.zero(); auto dim = this->model.getSpatialDimension(); const auto & boundary_fem = this->model.getFEEngineBoundary(); const auto & mesh = this->model.getMesh(); for (auto ghost_type : ghost_types) { for (const auto & type : mesh.elementTypes(dim - 1, ghost_type)) { auto nb_elements = mesh.getNbElement(type, ghost_type); auto nb_nodes_per_element = mesh.getNbNodesPerElement(type); const auto & connectivity = mesh.getConnectivity(type, ghost_type); // get shapes and compute integral const auto & shapes = boundary_fem.getShapes(type, ghost_type); Array area(nb_elements, nb_nodes_per_element); boundary_fem.integrate(shapes, area, nb_nodes_per_element, type, ghost_type); if (this->contact_surfaces.empty()) { AKANTU_DEBUG_WARNING( "No surfaces in ntn base contact." << " You have to define the lumped boundary by yourself."); } // loop over contact nodes for (auto && elem : elements(type, ghost_type)) { for (Int q = 0; q < nb_nodes_per_element; ++q) { auto node = connectivity(elem, q); auto node_index = nodes.find(node); AKANTU_DEBUG_ASSERT(node_index != Int(-1), "Could not find node " << node << " in the array!"); Real area_to_add = area(elem, q); boundary(node_index) += area_to_add; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::computeAcceleration(Array & acceleration) const { auto && dof_manager = dynamic_cast(model.getDOFManager()); const auto & b = dof_manager.getResidual(); acceleration.resize(b.size()); const auto & blocked_dofs = dof_manager.getGlobalBlockedDOFs(); const auto & A = dof_manager.getLumpedMatrix("M"); Array blocked_dofs_bool(blocked_dofs.size()); for (auto && data : zip(blocked_dofs, blocked_dofs_bool)) { std::get<1>(data) = (std::get<0>(data) != 0); } // pre-compute the acceleration // (not increment acceleration, because residual is still Kf) NonLinearSolverLumped::solveLumped(A, acceleration, b, this->model.getF_M2A(), blocked_dofs_bool); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::computeContactPressure() { AKANTU_DEBUG_IN(); - Int dim = this->model.getSpatialDimension(); - Real delta_t = this->model.getTimeStep(); - UInt nb_contact_nodes = getNbContactNodes(); + auto dim = this->model.getSpatialDimension(); + auto delta_t = this->model.getTimeStep(); + auto nb_contact_nodes = getNbContactNodes(); AKANTU_DEBUG_ASSERT(delta_t > 0., "Cannot compute contact pressure if no time step is set"); // synchronize data this->synch_registry->synchronize(SynchronizationTag::_cf_nodal); Array acceleration(0, dim); this->computeAcceleration(acceleration); // compute relative normal fields of displacement, velocity and acceleration Array r_disp(0, 1); Array r_velo(0, 1); Array r_acce(0, 1); Array r_old_acce(0, 1); computeNormalGap(r_disp); // computeRelativeNormalField(this->model.getCurrentPosition(), r_disp); computeRelativeNormalField(this->model.getVelocity(), r_velo); computeRelativeNormalField(acceleration, r_acce); computeRelativeNormalField(this->model.getAcceleration(), r_old_acce); AKANTU_DEBUG_ASSERT(r_disp.size() == nb_contact_nodes, "computeRelativeNormalField does not give back arrays " << "size == nb_contact_nodes. nb_contact_nodes = " << nb_contact_nodes << " | array size = " << r_disp.size()); // compute gap array for all nodes Array gap(nb_contact_nodes, 1); Real * gap_p = gap.data(); Real * r_disp_p = r_disp.data(); Real * r_velo_p = r_velo.data(); Real * r_acce_p = r_acce.data(); Real * r_old_acce_p = r_old_acce.data(); for (Int i = 0; i < nb_contact_nodes; ++i) { *gap_p = *r_disp_p + delta_t * *r_velo_p + delta_t * delta_t * *r_acce_p - 0.5 * delta_t * delta_t * *r_old_acce_p; // increment pointers gap_p++; r_disp_p++; r_velo_p++; r_acce_p++; r_old_acce_p++; } // check if gap is negative -> is in contact for (Int n = 0; n < nb_contact_nodes; ++n) { if (gap(n) <= 0.) { for (Int d = 0; d < dim; ++d) { this->contact_pressure(n, d) = this->impedance(n) * gap(n) / (2 * delta_t) * this->normals(n, d); } this->is_in_contact(n) = true; } else { for (Int d = 0; d < dim; ++d) { this->contact_pressure(n, d) = 0.; } this->is_in_contact(n) = false; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::applyContactPressure() { auto nb_contact_nodes = getNbContactNodes(); auto dim = this->model.getSpatialDimension(); auto & residual = this->model.getInternalForce(); for (Int n = 0; n < nb_contact_nodes; ++n) { auto slave = this->slaves(n); for (Int d = 0; d < dim; ++d) { // residual(master,d) += this->lumped_boundary(n,0) * // this->contact_pressure(n,d); residual(slave, d) -= this->lumped_boundary_slaves(n) * this->contact_pressure(n, d); } } } /* -------------------------------------------------------------------------- */ Int NTNBaseContact::getNodeIndex(Idx node) const { return this->slaves.find(node); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::printself(std::ostream & stream, int indent) const { std::string space(AKANTU_INDENT, indent); stream << space << "NTNBaseContact [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + slaves : " << std::endl; this->slaves.printself(stream, indent + 2); stream << space << " + normals : " << std::endl; this->normals.printself(stream, indent + 2); stream << space << " + contact_pressure : " << std::endl; this->contact_pressure.printself(stream, indent + 2); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void NTNBaseContact::syncArrays(SyncChoice sync_choice) { this->slaves.syncElements(sync_choice); this->normals.syncElements(sync_choice); this->is_in_contact.syncElements(sync_choice); this->contact_pressure.syncElements(sync_choice); this->lumped_boundary_slaves.syncElements(sync_choice); this->impedance.syncElements(sync_choice); } /* -------------------------------------------------------------------------- */ void NTNBaseContact::addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { AKANTU_DEBUG_IN(); const auto & nodal_filter = this->slaves.getArray(); #define ADD_FIELD(field_id, field, type) \ internalAddDumpFieldToDumper( \ dumper_name, field_id, \ std::make_unique< \ dumpers::NodalField, Array>>( \ field, 0, 0, &nodal_filter)) if (field_id == "displacement") { ADD_FIELD(field_id, this->model.getDisplacement(), Real); } else if (field_id == "mass") { ADD_FIELD(field_id, this->model.getMass(), Real); } else if (field_id == "velocity") { ADD_FIELD(field_id, this->model.getVelocity(), Real); } else if (field_id == "acceleration") { ADD_FIELD(field_id, this->model.getAcceleration(), Real); } else if (field_id == "external_force") { ADD_FIELD(field_id, this->model.getExternalForce(), Real); } else if (field_id == "internal_force") { ADD_FIELD(field_id, this->model.getInternalForce(), Real); } else if (field_id == "blocked_dofs") { ADD_FIELD(field_id, this->model.getBlockedDOFs(), bool); } else if (field_id == "increment") { ADD_FIELD(field_id, this->model.getIncrement(), Real); } else if (field_id == "normal") { internalAddDumpFieldToDumper( dumper_name, field_id, std::make_unique>(this->normals.getArray())); } else if (field_id == "contact_pressure") { internalAddDumpFieldToDumper(dumper_name, field_id, std::make_unique>( this->contact_pressure.getArray())); } else if (field_id == "is_in_contact") { internalAddDumpFieldToDumper(dumper_name, field_id, std::make_unique>( this->is_in_contact.getArray())); } else if (field_id == "lumped_boundary_slave") { internalAddDumpFieldToDumper(dumper_name, field_id, std::make_unique>( this->lumped_boundary_slaves.getArray())); } else if (field_id == "impedance") { internalAddDumpFieldToDumper(dumper_name, field_id, std::make_unique>( this->impedance.getArray())); } else { std::cerr << "Could not add field '" << field_id << "' to the dumper. Just ignored it." << std::endl; } #undef ADD_FIELD AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/packages/core.cmake b/packages/core.cmake index 2bec55309..1793a72c8 100644 --- a/packages/core.cmake +++ b/packages/core.cmake @@ -1,445 +1,444 @@ #=============================================================================== # @file core.cmake # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Mon Nov 21 2011 # @date last modification: Fri Apr 09 2021 # # @brief package description for core # # # @section LICENSE # # Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License along # with Akantu. If not, see . # #=============================================================================== package_declare(core NOT_OPTIONAL DESCRIPTION "core package for Akantu" FEATURES_PUBLIC cxx_strong_enums cxx_defaulted_functions cxx_deleted_functions cxx_auto_type cxx_decltype_auto FEATURES_PRIVATE cxx_lambdas cxx_nullptr cxx_range_for cxx_delegating_constructors DEPENDS INTERFACE akantu_iterators Boost Eigen3 ) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") package_set_compile_flags(core CXX "-Wall -Wextra -pedantic") else() package_set_compile_flags(core CXX "-Wall") endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0.0) - message(blip) package_set_compile_flags(core CXX "-Wall -Wextra -pedantic -Wno-attributes") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.9)) package_set_compile_flags(core CXX "-Wall -Wextra -pedantic -Wno-undefined-var-template") endif() package_declare_sources(core common/aka_array.cc common/aka_array.hh common/aka_array_filter.hh common/aka_array_tmpl.hh common/aka_array_printer.hh common/aka_bbox.hh common/aka_blas_lapack.hh common/aka_circular_array.hh common/aka_circular_array_inline_impl.hh common/aka_common.cc common/aka_common.hh common/aka_common_inline_impl.hh common/aka_csr.hh common/aka_element_classes_info_inline_impl.hh common/aka_enum_macros.hh common/aka_error.cc common/aka_error.hh common/aka_event_handler_manager.hh common/aka_extern.cc common/aka_factory.hh common/aka_fwd.hh common/aka_grid_dynamic.hh common/aka_math.cc common/aka_math.hh common/aka_math_tmpl.hh common/aka_named_argument.hh common/aka_random_generator.hh common/aka_safe_enum.hh common/aka_tensor.hh common/aka_types.hh common/aka_types_eigen_matrix_plugin.hh common/aka_types_eigen_matrix_base_plugin.hh common/aka_types_eigen_plain_object_base_plugin.hh common/aka_view_iterators.hh common/aka_voigthelper.hh common/aka_voigthelper_tmpl.hh common/aka_voigthelper.cc common/aka_warning.hh common/aka_warning_restore.hh fe_engine/element_class.hh fe_engine/element_class_helper.hh fe_engine/element_class_tmpl.hh fe_engine/element_classes/element_class_hexahedron_8_inline_impl.hh fe_engine/element_classes/element_class_hexahedron_20_inline_impl.hh fe_engine/element_classes/element_class_pentahedron_6_inline_impl.hh fe_engine/element_classes/element_class_pentahedron_15_inline_impl.hh fe_engine/element_classes/element_class_point_1_inline_impl.hh fe_engine/element_classes/element_class_quadrangle_4_inline_impl.hh fe_engine/element_classes/element_class_quadrangle_8_inline_impl.hh fe_engine/element_classes/element_class_segment_2_inline_impl.hh fe_engine/element_classes/element_class_segment_3_inline_impl.hh fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.hh fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.hh fe_engine/element_classes/element_class_triangle_3_inline_impl.hh fe_engine/element_classes/element_class_triangle_6_inline_impl.hh fe_engine/element_type_conversion.hh fe_engine/fe_engine.cc fe_engine/fe_engine.hh fe_engine/fe_engine_inline_impl.hh fe_engine/fe_engine_template.hh fe_engine/fe_engine_template_tmpl_field.hh fe_engine/fe_engine_template_tmpl.hh fe_engine/geometrical_element_property.hh fe_engine/geometrical_element_property.cc fe_engine/gauss_integration.cc fe_engine/gauss_integration_tmpl.hh fe_engine/integrator.hh fe_engine/integrator_gauss.hh fe_engine/integrator_gauss_inline_impl.hh fe_engine/interpolation_element_tmpl.hh fe_engine/integration_point.hh fe_engine/shape_functions.hh fe_engine/shape_functions.cc fe_engine/shape_functions_inline_impl.hh fe_engine/shape_lagrange_base.cc fe_engine/shape_lagrange_base.hh fe_engine/shape_lagrange_base_inline_impl.hh fe_engine/shape_lagrange.hh fe_engine/shape_lagrange_inline_impl.hh fe_engine/element.hh io/dumper/dumpable.hh io/dumper/dumpable.cc io/dumper/dumpable_dummy.hh io/dumper/dumpable_inline_impl.hh io/dumper/dumper_field.hh io/dumper/dumper_material_padders.hh io/dumper/dumper_filtered_connectivity.hh io/dumper/dumper_element_partition.hh io/mesh_io.cc io/mesh_io.hh io/mesh_io/mesh_io_diana.cc io/mesh_io/mesh_io_diana.hh io/mesh_io/mesh_io_msh.cc io/mesh_io/mesh_io_msh.hh #io/model_io.cc #io/model_io.hh io/parser/algebraic_parser.hh io/parser/input_file_parser.hh io/parser/parsable.cc io/parser/parsable.hh io/parser/parser.cc io/parser/parser_real.cc io/parser/parser_random.cc io/parser/parser_types.cc io/parser/parser_input_files.cc io/parser/parser.hh io/parser/parser_tmpl.hh io/parser/parser_grammar_tmpl.hh io/parser/cppargparse/cppargparse.hh io/parser/cppargparse/cppargparse.cc io/parser/cppargparse/cppargparse_tmpl.hh io/parser/parameter_registry.cc io/parser/parameter_registry.hh io/parser/parameter_registry_tmpl.hh mesh/element_group.cc mesh/element_group.hh mesh/element_group_inline_impl.hh mesh/element_type_map.cc mesh/element_type_map.hh mesh/element_type_map_tmpl.hh mesh/element_type_map_filter.hh mesh/group_manager.cc mesh/group_manager.hh mesh/group_manager_inline_impl.hh mesh/mesh.cc mesh/mesh.hh mesh/mesh_periodic.cc mesh/mesh_accessor.hh mesh/mesh_events.hh mesh/mesh_filter.hh mesh/mesh_global_data_updater.hh mesh/mesh_data.cc mesh/mesh_data.hh mesh/mesh_data_tmpl.hh mesh/mesh_inline_impl.hh mesh/node_group.cc mesh/node_group.hh mesh/node_group_inline_impl.hh mesh/mesh_iterators.hh mesh_utils/mesh_partition.cc mesh_utils/mesh_partition.hh mesh_utils/mesh_partition/mesh_partition_mesh_data.cc mesh_utils/mesh_partition/mesh_partition_mesh_data.hh mesh_utils/mesh_partition/mesh_partition_scotch.hh mesh_utils/mesh_utils_pbc.cc mesh_utils/mesh_utils.cc mesh_utils/mesh_utils.hh mesh_utils/mesh_utils_distribution.cc mesh_utils/mesh_utils_distribution.hh mesh_utils/mesh_utils.hh mesh_utils/mesh_utils_inline_impl.hh mesh_utils/global_ids_updater.hh mesh_utils/global_ids_updater.cc mesh_utils/global_ids_updater_inline_impl.hh model/common/boundary_condition/boundary_condition.hh model/common/boundary_condition/boundary_condition_functor.hh model/common/boundary_condition/boundary_condition_functor_inline_impl.hh model/common/boundary_condition/boundary_condition_tmpl.hh model/common/non_local_toolbox/neighborhood_base.hh model/common/non_local_toolbox/neighborhood_base.cc model/common/non_local_toolbox/neighborhood_base_inline_impl.hh model/common/non_local_toolbox/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh model/common/non_local_toolbox/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc model/common/non_local_toolbox/neighborhoods_criterion_evaluation/neighborhood_max_criterion_inline_impl.hh model/common/non_local_toolbox/non_local_manager.hh model/common/non_local_toolbox/non_local_manager.cc model/common/non_local_toolbox/non_local_manager_inline_impl.hh model/common/non_local_toolbox/non_local_manager_callback.hh model/common/non_local_toolbox/non_local_neighborhood_base.hh model/common/non_local_toolbox/non_local_neighborhood_base.cc model/common/non_local_toolbox/non_local_neighborhood.hh model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh model/common/non_local_toolbox/non_local_neighborhood_inline_impl.hh model/common/non_local_toolbox/base_weight_function.hh model/common/non_local_toolbox/base_weight_function.cc model/common/non_local_toolbox/base_weight_function_inline_impl.hh model/common/model_solver.cc model/common/model_solver.hh model/common/solver_callback.hh model/common/solver_callback.cc model/common/dof_manager/dof_manager.cc model/common/dof_manager/dof_manager.hh model/common/dof_manager/dof_manager_default.cc model/common/dof_manager/dof_manager_default.hh model/common/dof_manager/dof_manager_default_inline_impl.hh model/common/dof_manager/dof_manager_inline_impl.hh model/common/non_linear_solver/non_linear_solver.cc model/common/non_linear_solver/non_linear_solver.hh model/common/non_linear_solver/non_linear_solver_default.hh model/common/non_linear_solver/non_linear_solver_lumped.cc model/common/non_linear_solver/non_linear_solver_lumped.hh model/common/time_step_solvers/time_step_solver.hh model/common/time_step_solvers/time_step_solver.cc model/common/time_step_solvers/time_step_solver_default.cc model/common/time_step_solvers/time_step_solver_default.hh model/common/time_step_solvers/time_step_solver_default_explicit.hh model/common/integration_scheme/generalized_trapezoidal.cc model/common/integration_scheme/generalized_trapezoidal.hh model/common/integration_scheme/integration_scheme.cc model/common/integration_scheme/integration_scheme.hh model/common/integration_scheme/integration_scheme_1st_order.cc model/common/integration_scheme/integration_scheme_1st_order.hh model/common/integration_scheme/integration_scheme_2nd_order.cc model/common/integration_scheme/integration_scheme_2nd_order.hh model/common/integration_scheme/newmark-beta.cc model/common/integration_scheme/newmark-beta.hh model/common/integration_scheme/pseudo_time.cc model/common/integration_scheme/pseudo_time.hh model/model.cc model/model.hh model/model_inline_impl.hh model/model_options.hh solver/solver_vector.hh solver/solver_vector_default.hh solver/solver_vector_default_tmpl.hh solver/solver_vector_distributed.cc solver/solver_vector_distributed.hh solver/sparse_matrix.cc solver/sparse_matrix.hh solver/sparse_matrix_aij.cc solver/sparse_matrix_aij.hh solver/sparse_matrix_aij_inline_impl.hh solver/sparse_matrix_inline_impl.hh solver/sparse_solver.cc solver/sparse_solver.hh solver/sparse_solver_inline_impl.hh solver/terms_to_assemble.hh synchronizer/communication_buffer_inline_impl.hh synchronizer/communication_descriptor.hh synchronizer/communication_descriptor_tmpl.hh synchronizer/communication_request.hh synchronizer/communication_tag.hh synchronizer/communications.hh synchronizer/communications_tmpl.hh synchronizer/communicator.cc synchronizer/communicator.hh synchronizer/communicator_dummy_inline_impl.hh synchronizer/communicator_event_handler.hh synchronizer/communicator_inline_impl.hh synchronizer/data_accessor.cc synchronizer/data_accessor.hh synchronizer/dof_synchronizer.cc synchronizer/dof_synchronizer.hh synchronizer/dof_synchronizer_inline_impl.hh synchronizer/element_info_per_processor.cc synchronizer/element_info_per_processor.hh synchronizer/element_info_per_processor_tmpl.hh synchronizer/element_synchronizer.cc synchronizer/element_synchronizer.hh synchronizer/facet_synchronizer.cc synchronizer/facet_synchronizer.hh synchronizer/facet_synchronizer_inline_impl.hh synchronizer/grid_synchronizer.cc synchronizer/grid_synchronizer.hh synchronizer/grid_synchronizer_tmpl.hh synchronizer/master_element_info_per_processor.cc synchronizer/node_info_per_processor.cc synchronizer/node_info_per_processor.hh synchronizer/node_synchronizer.cc synchronizer/node_synchronizer.hh synchronizer/node_synchronizer_inline_impl.hh synchronizer/periodic_node_synchronizer.cc synchronizer/periodic_node_synchronizer.hh synchronizer/slave_element_info_per_processor.cc synchronizer/synchronizer.cc synchronizer/synchronizer.hh synchronizer/synchronizer_impl.hh synchronizer/synchronizer_impl_tmpl.hh synchronizer/synchronizer_registry.cc synchronizer/synchronizer_registry.hh synchronizer/synchronizer_tmpl.hh synchronizer/communication_buffer.hh ) set(AKANTU_SPIRIT_SOURCES io/mesh_io/mesh_io_abaqus.cc io/parser/parser_real.cc io/parser/parser_random.cc io/parser/parser_types.cc io/parser/parser_input_files.cc PARENT_SCOPE ) package_declare_elements(core ELEMENT_TYPES _point_1 _segment_2 _segment_3 _triangle_3 _triangle_6 _quadrangle_4 _quadrangle_8 _tetrahedron_4 _tetrahedron_10 _pentahedron_6 _pentahedron_15 _hexahedron_8 _hexahedron_20 KIND regular GEOMETRICAL_TYPES _gt_point _gt_segment_2 _gt_segment_3 _gt_triangle_3 _gt_triangle_6 _gt_quadrangle_4 _gt_quadrangle_8 _gt_tetrahedron_4 _gt_tetrahedron_10 _gt_hexahedron_8 _gt_hexahedron_20 _gt_pentahedron_6 _gt_pentahedron_15 INTERPOLATION_TYPES _itp_lagrange_point_1 _itp_lagrange_segment_2 _itp_lagrange_segment_3 _itp_lagrange_triangle_3 _itp_lagrange_triangle_6 _itp_lagrange_quadrangle_4 _itp_serendip_quadrangle_8 _itp_lagrange_tetrahedron_4 _itp_lagrange_tetrahedron_10 _itp_lagrange_hexahedron_8 _itp_serendip_hexahedron_20 _itp_lagrange_pentahedron_6 _itp_lagrange_pentahedron_15 GEOMETRICAL_SHAPES _gst_point _gst_triangle _gst_square _gst_prism GAUSS_INTEGRATION_TYPES _git_point _git_segment _git_triangle _git_tetrahedron _git_pentahedron INTERPOLATION_KIND _itk_lagrangian FE_ENGINE_LISTS gradient_on_integration_points interpolate_on_integration_points interpolate compute_normals_on_integration_points inverse_map contains compute_shapes compute_shapes_derivatives get_N compute_dnds compute_d2nds2 compute_jmat get_shapes_derivatives lagrange_base assemble_fields ) find_program(READLINK_COMMAND readlink) find_program(ADDR2LINE_COMMAND addr2line) find_program(PATCH_COMMAND patch) mark_as_advanced(READLINK_COMMAND) mark_as_advanced(ADDR2LINE_COMMAND) package_declare_extra_files_to_package(core SOURCES common/aka_element_classes_info.hh.in common/aka_config.hh.in ) diff --git a/python/py_group_manager.cc b/python/py_group_manager.cc index 94e006ef2..ada654e20 100644 --- a/python/py_group_manager.cc +++ b/python/py_group_manager.cc @@ -1,178 +1,176 @@ /** * @file py_group_manager.cc * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Sun Jun 16 2019 * @date last modification: Mon Dec 02 2019 * * @brief pybind11 interface to GroupManager, ElementGroup and NodeGroup * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "py_aka_array.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void register_group_manager(py::module & mod) { /* ------------------------------------------------------------------------ */ py::class_(mod, "NodeGroup") .def( "getNodes", [](NodeGroup & self) -> decltype(auto) { return self.getNodes(); }, py::return_value_policy::reference) .def("__len__", &NodeGroup::size) .def( "__iter__", [](const NodeGroup & self) { return py::make_iterator(self.begin(), self.end()); }, py::keep_alive<0, 1>()) - .def("__contains__", - [](const NodeGroup & self, UInt node) { - return self.find(node) != UInt(-1); - }) + .def("__contains__", [](const NodeGroup & self, + UInt node) { return self.find(node) != -1; }) .def("getName", &NodeGroup::getName) .def("clear", &NodeGroup::clear) .def("empty", &NodeGroup::empty) .def("append", &NodeGroup::append) .def("add", &NodeGroup::add, py::arg("node"), py::arg("check_for_duplicate") = true) .def("remove", &NodeGroup::add); /* ------------------------------------------------------------------------ */ py::class_(mod, "ElementGroup") .def( "getNodeGroup", [](ElementGroup & self) -> decltype(auto) { return self.getNodeGroup(); }, py::return_value_policy::reference) .def("getName", &ElementGroup::getName) .def( "getElements", [](ElementGroup & self) -> decltype(auto) { return self.getElements(); }, py::return_value_policy::reference) .def( "getNodeGroup", [](ElementGroup & self) -> decltype(auto) { return self.getNodeGroup(); }, py::return_value_policy::reference) .def("__len__", [](const ElementGroup & self) { return self.size(); }) .def("clear", [](ElementGroup & self) { self.clear(); }) .def("empty", &ElementGroup::empty) .def("append", &ElementGroup::append) .def( "add", [](ElementGroup & self, const Element & element, bool add_nodes, bool check_for_duplicate) { self.add(element, add_nodes, check_for_duplicate); }, py::arg("element"), py::arg("add_nodes") = false, py::arg("check_for_duplicate") = true) .def("fillFromNodeGroup", &ElementGroup::fillFromNodeGroup) .def("addDimension", &ElementGroup::addDimension); /* ------------------------------------------------------------------------ */ py::class_(mod, "GroupManager") .def( "getElementGroup", [](GroupManager & self, const std::string & name) -> decltype(auto) { return self.getElementGroup(name); }, py::return_value_policy::reference) .def("iterateElementGroups", [](GroupManager & self) -> decltype(auto) { std::vector> groups; for (auto & group : self.iterateElementGroups()) { groups.emplace_back(group); } return groups; }) .def("iterateNodeGroups", [](GroupManager & self) -> decltype(auto) { std::vector> groups; for (auto & group : self.iterateNodeGroups()) { groups.emplace_back(group); } return groups; }) .def("createNodeGroup", &GroupManager::createNodeGroup, py::return_value_policy::reference) .def( "createElementGroup", [](GroupManager & self, const std::string & id, Int spatial_dimension, bool b) -> decltype(auto) { return self.createElementGroup(id, spatial_dimension, b); }, py::return_value_policy::reference) .def("createGroupsFromMeshDataUInt", &GroupManager::createGroupsFromMeshData) .def("createElementGroupFromNodeGroup", &GroupManager::createElementGroupFromNodeGroup, py::arg("name"), py::arg("node_group"), py::arg("dimension") = _all_dimensions) .def( "getNodeGroup", [](GroupManager & self, const std::string & name) -> decltype(auto) { return self.getNodeGroup(name); }, py::return_value_policy::reference) .def( "nodeGroups", [](GroupManager & self) { std::vector groups; for (auto & g : self.iterateNodeGroups()) { groups.push_back(&g); } return groups; }, py::return_value_policy::reference) .def( "elementGroups", [](GroupManager & self) { std::vector groups; for (auto & g : self.iterateElementGroups()) { groups.push_back(&g); } return groups; }, py::return_value_policy::reference) .def("createBoundaryGroupFromGeometry", &GroupManager::createBoundaryGroupFromGeometry); } } // namespace akantu diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 496a9c5a6..d67cbac1c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,271 +1,270 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Mon Jun 14 2010 # @date last modification: Tue Feb 13 2018 # # @brief CMake file for the library # # @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 . # #=============================================================================== #=============================================================================== # Package Management #=============================================================================== package_get_all_source_files( AKANTU_LIBRARY_SRCS AKANTU_LIBRARY_PUBLIC_HDRS AKANTU_LIBRARY_PRIVATE_HDRS ) package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) package_get_all_external_informations( PRIVATE_INCLUDE AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR LIBRARIES AKANTU_EXTERNAL_LIBRARIES ) package_get_all_compilation_flags(CXX _cxx_flags) set(AKANTU_EXTRA_CXX_FLAGS "${_cxx_flags}" CACHE STRING "Extra flags defined by loaded packages" FORCE) mark_as_advanced(AKANTU_EXTRA_CXX_FLAGS) foreach(src_ ${AKANTU_SPIRIT_SOURCES}) set_property(SOURCE ${src_} PROPERTY COMPILE_FLAGS "-g0 -Werror") endforeach() #=========================================================================== # header for blas/lapack (any other fortran libraries) #=========================================================================== package_is_activated(BLAS _blas_activated) package_is_activated(LAPACK _lapack_activated) if(_blas_activated OR _lapack_activated) if(CMAKE_Fortran_COMPILER) # ugly hack set(CMAKE_Fortran_COMPILER_LOADED TRUE) endif() include(FortranCInterface) FortranCInterface_HEADER( "${CMAKE_CURRENT_BINARY_DIR}/aka_fortran_mangling.hh" MACRO_NAMESPACE "AKA_FC_") mark_as_advanced(CDEFS) list(APPEND AKANTU_LIBRARY_PUBLIC_HDRS "${CMAKE_CURRENT_BINARY_DIR}/aka_fortran_mangling.hh" ) endif() list(APPEND AKANTU_LIBRARY_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}") set(AKANTU_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} ${AKANTU_LIBRARY_INCLUDE_DIRS} CACHE INTERNAL "Internal include directories to link with Akantu as a subproject") #=========================================================================== # configurations #=========================================================================== package_get_all_material_includes(AKANTU_MATERIAL_INCLUDES) package_get_all_material_lists(AKANTU_MATERIAL_LISTS) configure_file(model/solid_mechanics/material_list.hh.in "${CMAKE_CURRENT_BINARY_DIR}/material_list.hh" @ONLY) package_get_element_lists() configure_file(common/aka_element_classes_info.hh.in "${CMAKE_CURRENT_BINARY_DIR}/aka_element_classes_info.hh" @ONLY) configure_file(common/aka_config.hh.in "${CMAKE_CURRENT_BINARY_DIR}/aka_config.hh" @ONLY) list(APPEND AKANTU_LIBRARY_PUBLIC_HDRS "${CMAKE_CURRENT_BINARY_DIR}/material_list.hh" "${CMAKE_CURRENT_BINARY_DIR}/aka_element_classes_info.hh" "${CMAKE_CURRENT_BINARY_DIR}/aka_config.hh") #=============================================================================== # Debug infos #=============================================================================== set(AKANTU_GDB_DIR ${PROJECT_SOURCE_DIR}/cmake) if(UNIX AND NOT APPLE) string(TOUPPER "${CMAKE_BUILD_TYPE}" _u_build_type) if(_u_build_type STREQUAL "DEBUG" OR _u_build_type STREQUAL "RELWITHDEBINFO") configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in "${PROJECT_BINARY_DIR}/libakantu-gdb.py" @ONLY) configure_file(${PROJECT_SOURCE_DIR}/cmake/akantu-debug.cc.in "${PROJECT_BINARY_DIR}/akantu-debug.cc" @ONLY) list(APPEND AKANTU_LIBRARY_SRCS ${PROJECT_BINARY_DIR}/akantu-debug.cc) endif() else() find_program(GDB_EXECUTABLE gdb) if(GDB_EXECUTABLE) execute_process(COMMAND ${GDB_EXECUTABLE} --batch -x "${PROJECT_SOURCE_DIR}/cmake/gdb_python_path" OUTPUT_VARIABLE AKANTU_PYTHON_GDB_DIR ERROR_QUIET RESULT_VARIABLE _res) if(_res EQUAL 0 AND UNIX) set(GDB_USER_CONFIG $ENV{HOME}/.gdb/auto-load) file(MAKE_DIRECTORY ${GDB_USER_CONFIG}) configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in "${GDB_USER_CONFIG}/${CMAKE_SHARED_LIBRARY_PREFIX}akantu${CMAKE_SHARED_LIBRARY_SUFFIX}.${AKANTU_VERSION}-gdb.py" @ONLY) endif() endif() endif() #=============================================================================== # GIT info #=============================================================================== #include(AkantuBuildOptions) #git_version_info(akantu_git_info ALL # OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/akantu_git_info.hh # ) #list(APPEND AKANTU_LIBRARY_SRCS ${CMAKE_CURRENT_BINARY_DIR}/akantu_git_info.hh) #=============================================================================== # Library generation #=============================================================================== add_library(akantu ${AKANTU_LIBRARY_SRCS}) target_include_directories(akantu PRIVATE $ INTERFACE $ ) # small trick for build includes in public set_property(TARGET akantu APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES $) target_include_directories(akantu SYSTEM PUBLIC ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR} ) target_include_directories(akantu SYSTEM PRIVATE ${AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR} ) target_link_libraries(akantu PUBLIC ${AKANTU_EXTERNAL_LIBRARIES}) -message("cxx_flags: ${_cxx_flags}") +separate_arguments(_separated_cxx_flags UNIX_COMMAND ${_cxx_flags}) +target_compile_options(akantu PUBLIC ${_separated_cxx_flags}) set_target_properties(akantu PROPERTIES ${AKANTU_LIBRARY_PROPERTIES} # this contains the version - COMPILE_FLAGS "${_cxx_flags}" - #PRIVATE_HEADER ${AKANTU_LIBRARY_PRIVATE_HDRS} ) if(NOT AKANTU_SHARED) set_property(TARGET akantu PROPERTY POSITION_INDEPENDENT_CODE ${AKANTU_POSITION_INDEPENDENT}) endif() if(AKANTU_LIBRARY_PUBLIC_HDRS) set_property(TARGET akantu PROPERTY PUBLIC_HEADER ${AKANTU_LIBRARY_PUBLIC_HDRS}) endif() if(AKANTU_LIBRARY_PRIVATE_HDRS) set_property(TARGET akantu PROPERTY PRIVATE_HEADER ${AKANTU_LIBRARY_PRIVATE_HDRS}) endif() if(NOT CMAKE_VERSION VERSION_LESS 3.1) package_get_all_features_public(_PUBLIC_features) package_get_all_features_private(_PRIVATE_features) foreach(_type PRIVATE PUBLIC) if(_${_type}_features) target_compile_features(akantu ${_type} ${_${_type}_features}) endif() endforeach() else() set_target_properties(akantu PROPERTIES CXX_STANDARD 14 ) endif() package_get_all_extra_dependencies(_extra_target_dependencies) if(_extra_target_dependencies) # This only adding todo: find a solution for when a dependency was add the is removed... add_dependencies(akantu ${_extra_target_dependencies}) endif() package_get_all_export_list(AKANTU_EXPORT_LIST) list(APPEND AKANTU_EXPORT_LIST akantu) # TODO separate public from private headers install(TARGETS akantu EXPORT ${AKANTU_TARGETS_EXPORT} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Akantu_runtime # NAMELINK_ONLY # LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # COMPONENT Akantu_development # NAMELINK_SKIP Akantu_development ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Akantu_runtime RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Akantu_runtime PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/akantu/ COMPONENT Akantu_development ) if("${AKANTU_TARGETS_EXPORT}" STREQUAL "AkantuTargets") install(EXPORT AkantuTargets DESTINATION lib/cmake/${PROJECT_NAME} COMPONENT dev) #Export for build tree export(EXPORT AkantuTargets FILE "${CMAKE_BINARY_DIR}/AkantuTargets.cmake") export(PACKAGE Akantu) endif() #=============================================================================== # Adding module names for debug package_get_all_packages(_pkg_list) foreach(_pkg ${_pkg_list}) _package_get_real_name(${_pkg} _pkg_name) _package_get_source_files(${_pkg} _srcs _public_hdrs _private_hdrs) string(TOLOWER "${_pkg_name}" _l_package_name) set_property(SOURCE ${_srcs} ${_public_hdrs} ${_private_hdrs} APPEND PROPERTY COMPILE_DEFINITIONS AKANTU_MODULE=${_l_package_name}) endforeach() # print out the list of materials generate_material_list() register_target_to_tidy(akantu) register_tidy_all(${AKANTU_LIBRARY_SRCS}) register_code_to_format( ${AKANTU_LIBRARY_SRCS} ${AKANTU_LIBRARY_PUBLIC_HDRS} ${AKANTU_LIBRARY_PRIVATE_HDRS} ) diff --git a/src/common/aka_math.hh b/src/common/aka_math.hh index 0ac584766..3ca8766b1 100644 --- a/src/common/aka_math.hh +++ b/src/common/aka_math.hh @@ -1,170 +1,173 @@ /** * @file aka_math.hh * * @author Ramin Aghababaei * @author Guillaume Anciaux * @author Marion Estelle Chambart * @author David Simon Kammer * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Leonardo Snozzi * @author Peter Spijker * @author Marco Vocialta * * @date creation: Wed Aug 04 2010 * @date last modification: Tue Feb 09 2021 * * @brief mathematical operations * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_types.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef AKANTU_AKA_MATH_H_ #define AKANTU_AKA_MATH_H_ namespace akantu { /* -------------------------------------------------------------------------- */ namespace Math { /// tolerance for functions that need one extern Real tolerance; // NOLINT /* ------------------------------------------------------------------------ */ /* Geometry */ /* ------------------------------------------------------------------------ */ /// compute normal a normal to a vector template ::value> * = nullptr> inline Vector normal(const Eigen::MatrixBase & vec); template ::value> * = nullptr> inline Vector normal(const Eigen::MatrixBase & /*vec*/) { AKANTU_TO_IMPLEMENT(); } /// compute normal a normal to a vector template ::value> * = nullptr> inline Vector normal(const Eigen::MatrixBase & vec1, const Eigen::MatrixBase & vec2); /// compute the tangents to an array of normal vectors void compute_tangents(const Array & normals, Array & tangents); /// radius of the in-circle of a triangle in 2d space template - static inline Real triangle_inradius(const Eigen::MatrixBase & coord1, - const Eigen::MatrixBase & coord2, - const Eigen::MatrixBase & coord3); + static constexpr inline Real + triangle_inradius(const Eigen::MatrixBase & coord1, + const Eigen::MatrixBase & coord2, + const Eigen::MatrixBase & coord3); /// radius of the in-circle of a tetrahedron template - static inline Real tetrahedron_inradius(const Eigen::MatrixBase & coord1, - const Eigen::MatrixBase & coord2, - const Eigen::MatrixBase & coord3, - const Eigen::MatrixBase & coord4); + static constexpr inline Real + tetrahedron_inradius(const Eigen::MatrixBase & coord1, + const Eigen::MatrixBase & coord2, + const Eigen::MatrixBase & coord3, + const Eigen::MatrixBase & coord4); /// volume of a tetrahedron template - static inline Real tetrahedron_volume(const Eigen::MatrixBase & coord1, - const Eigen::MatrixBase & coord2, - const Eigen::MatrixBase & coord3, - const Eigen::MatrixBase & coord4); + static constexpr inline Real + tetrahedron_volume(const Eigen::MatrixBase & coord1, + const Eigen::MatrixBase & coord2, + const Eigen::MatrixBase & coord3, + const Eigen::MatrixBase & coord4); /// compute the barycenter of n points template inline void barycenter(const Eigen::MatrixBase & coord, Eigen::MatrixBase & barycenter); /// test if two scalar are equal within a given tolerance inline bool are_float_equal(Real x, Real y); /// test if two vectors are equal within a given tolerance inline bool are_vector_equal(Int n, Real * x, Real * y); #ifdef isnan #error \ "You probably included which is incompatible with aka_math please use\ or add a \"#undef isnan\" before akantu includes" #endif /// test if a real is a NaN inline bool isnan(Real x); /// test if the line x and y intersects each other inline bool intersects(Real x_min, Real x_max, Real y_min, Real y_max); /// test if a is in the range [x_min, x_max] inline bool is_in_range(Real a, Real x_min, Real x_max); inline Real getTolerance() { return Math::tolerance; } inline void setTolerance(Real tol) { Math::tolerance = tol; } template inline T pow(T x); template ::value and std::is_integral::value> * = nullptr> inline Real kronecker(T1 i, T2 j) { return static_cast(i == j); } /* -------------------------------------------------------------------------- */ template static inline constexpr T pow(T x, int p) { return p == 0 ? T(1) : (pow(x, p - 1) * x); } /// reduce all the values of an array, the summation is done in place and the /// array is modified Real reduce(Array & array); template class NewtonRaphson { public: NewtonRaphson(Real tolerance, Int max_iteration) : tolerance(tolerance), max_iteration(max_iteration) {} template T solve(const Functor & funct, const T & x_0); private: Real tolerance; Int max_iteration; }; template struct NewtonRaphsonFunctor { explicit NewtonRaphsonFunctor(const std::string & name) : name(name) {} virtual T f(const T & x) const = 0; virtual T f_prime(const T & x) const = 0; std::string name; }; } // namespace Math } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "aka_math_tmpl.hh" #endif /* AKANTU_AKA_MATH_H_ */ diff --git a/src/common/aka_math_tmpl.hh b/src/common/aka_math_tmpl.hh index 06122e66d..27e801822 100644 --- a/src/common/aka_math_tmpl.hh +++ b/src/common/aka_math_tmpl.hh @@ -1,238 +1,241 @@ /** * @file aka_math_tmpl.hh * * @author Ramin Aghababaei * @author Guillaume Anciaux * @author Alejandro M. Aragón * @author Emil Gallyamov * @author David Simon Kammer * @author Daniel Pino Muñoz * @author Mohit Pundir * @author Mathilde Radiguet * @author Nicolas Richart * @author Leonardo Snozzi * @author Peter Spijker * @author Marco Vocialta * * @date creation: Wed Aug 04 2010 * @date last modification: Fri Dec 11 2020 * * @brief Implementation of the inline functions of the math toolkit * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_blas_lapack.hh" #include "aka_math.hh" #include "aka_types.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ namespace akantu { namespace Math { /* ------------------------------------------------------------------------ */ template ::value> *> inline Vector normal(const Eigen::MatrixBase & vec) { Vector normal_; AKANTU_DEBUG_ASSERT(vec.cols() == 1 and vec.rows() == 2, "Vec is not of the proper size"); Vector vec_(vec); normal_[0] = vec_[1]; normal_[1] = -vec_[0]; normal_ /= normal_.norm(); return normal_; } /* ------------------------------------------------------------------------ */ template *> inline Vector normal(const Eigen::MatrixBase & vec1, const Eigen::MatrixBase & vec2) { AKANTU_DEBUG_ASSERT(vec1.cols() == 1 and vec1.rows() == 3, "Vec is not of the proper size"); AKANTU_DEBUG_ASSERT(vec2.cols() == 1 and vec2.rows() == 3, "Vec is not of the proper size"); Vector vec1_(vec1); Vector vec2_(vec2); auto && normal = vec1_.cross(vec2_); normal /= normal.norm(); return normal.eval(); } /* ------------------------------------------------------------------------ */ template - static inline Real triangle_inradius(const Eigen::MatrixBase & coord1, - const Eigen::MatrixBase & coord2, - const Eigen::MatrixBase & coord3) { + constexpr inline Real + triangle_inradius(const Eigen::MatrixBase & coord1, + const Eigen::MatrixBase & coord2, + const Eigen::MatrixBase & coord3) { auto a = coord1.distance(coord2); auto b = coord2.distance(coord3); auto c = coord1.distance(coord3); auto s = (a + b + c) / 2.; return std::sqrt((s - a) * (s - b) * (s - c) / s); } /* ------------------------------------------------------------------------ */ template - inline Real tetrahedron_volume(const Eigen::MatrixBase & coord1, - const Eigen::MatrixBase & coord2, - const Eigen::MatrixBase & coord3, - const Eigen::MatrixBase & coord4) { + constexpr inline Real + tetrahedron_volume(const Eigen::MatrixBase & coord1, + const Eigen::MatrixBase & coord2, + const Eigen::MatrixBase & coord3, + const Eigen::MatrixBase & coord4) { Matrix xx; xx.col(0) = coord2; xx.col(1) = coord3; xx.col(2) = coord4; auto vol = xx.determinant(); xx.col(0) = coord1; vol -= xx.determinant(); xx.col(1) = coord2; vol += xx.determinant(); xx.col(2) = coord3; vol -= xx.determinant(); vol /= 6; return vol; } /* ------------------------------------------------------------------------ */ template - inline Real tetrahedron_inradius(const Eigen::MatrixBase & coord1, - const Eigen::MatrixBase & coord2, - const Eigen::MatrixBase & coord3, - const Eigen::MatrixBase & coord4) { + constexpr inline Real + tetrahedron_inradius(const Eigen::MatrixBase & coord1, + const Eigen::MatrixBase & coord2, + const Eigen::MatrixBase & coord3, + const Eigen::MatrixBase & coord4) { auto l12 = coord1.distance(coord2); auto l13 = coord1.distance(coord3); auto l14 = coord1.distance(coord4); auto l23 = coord2.distance(coord3); auto l24 = coord2.distance(coord4); auto l34 = coord3.distance(coord4); auto s1 = (l12 + l23 + l13) * 0.5; s1 = std::sqrt(s1 * (s1 - l12) * (s1 - l23) * (s1 - l13)); auto s2 = (l12 + l24 + l14) * 0.5; s2 = std::sqrt(s2 * (s2 - l12) * (s2 - l24) * (s2 - l14)); auto s3 = (l23 + l34 + l24) * 0.5; s3 = std::sqrt(s3 * (s3 - l23) * (s3 - l34) * (s3 - l24)); auto s4 = (l13 + l34 + l14) * 0.5; s4 = std::sqrt(s4 * (s4 - l13) * (s4 - l34) * (s4 - l14)); auto volume = Math::tetrahedron_volume(coord1, coord2, coord3, coord4); return 3 * volume / (s1 + s2 + s3 + s4); } /* ------------------------------------------------------------------------ */ template inline void barycenter(const Eigen::MatrixBase & coord, Eigen::MatrixBase & barycenter) { barycenter.zero(); for (auto && x : coord) { barycenter += x; } barycenter /= (Real)coord.cols(); } /* ------------------------------------------------------------------------ */ /// Combined absolute and relative tolerance test proposed in /// Real-time collision detection by C. Ericson (2004) inline bool are_float_equal(const Real x, const Real y) { Real abs_max = std::max(std::abs(x), std::abs(y)); abs_max = std::max(abs_max, Real(1.)); return std::abs(x - y) <= (tolerance * abs_max); } /* ------------------------------------------------------------------------ */ inline bool isnan(Real x) { #if defined(__INTEL_COMPILER) #pragma warning(push) #pragma warning(disable : 1572) #endif // defined(__INTEL_COMPILER) // x = x return false means x = quiet_NaN return !(x == x); #if defined(__INTEL_COMPILER) #pragma warning(pop) #endif // defined(__INTEL_COMPILER) } /* ------------------------------------------------------------------------ */ inline bool are_vector_equal(Int n, Real * x, Real * y) { bool test = true; for (Int i = 0; i < n; ++i) { test &= are_float_equal(x[i], y[i]); } return test; } /* ------------------------------------------------------------------------ */ inline bool intersects(Real x_min, Real x_max, Real y_min, Real y_max) { return not((x_max < y_min) or (x_min > y_max)); } /* ------------------------------------------------------------------------ */ inline bool is_in_range(Real a, Real x_min, Real x_max) { return ((a >= x_min) and (a <= x_max)); } /* ------------------------------------------------------------------------ */ template inline T pow(T x) { return (pow

(x) * x); } template <> inline Int pow<0, Int>(Int /*x*/) { return (1); } template <> inline Real pow<0, Real>(Real /*x*/) { return (1.); } /* ------------------------------------------------------------------------ */ template template T NewtonRaphson::solve(const Functor & funct, const T & x_0) { T x = x_0; T f_x = funct.f(x); Int iter = 0; while (std::abs(f_x) > this->tolerance && iter < this->max_iteration) { x -= f_x / funct.f_prime(x); f_x = funct.f(x); iter++; } AKANTU_DEBUG_ASSERT(iter < this->max_iteration, "Newton Raphson (" << funct.name << ") solve did not converge in " << this->max_iteration << " iterations (tolerance: " << this->tolerance << ")"); return x; } } // namespace Math } // namespace akantu diff --git a/src/common/aka_types.hh b/src/common/aka_types.hh index 28a8b990f..a180e5f2e 100644 --- a/src/common/aka_types.hh +++ b/src/common/aka_types.hh @@ -1,536 +1,536 @@ /** * @file aka_types.hh * * @author Nicolas Richart * * @date creation: Thu Feb 17 2011 * @date last modification: Wed Dec 09 2020 * * @brief description of the "simple" types * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_compatibilty_with_cpp_standard.hh" #include "aka_error.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include #include #ifndef AKANTU_AKA_TYPES_HH #define AKANTU_AKA_TYPES_HH namespace Eigen { template struct Map; template struct Matrix; template struct MatrixBase; } // namespace Eigen /* -------------------------------------------------------------------------- */ namespace aka { template struct is_eigen_map : public std::false_type {}; template struct is_eigen_map> : public std::true_type {}; /* -------------------------------------------------------------------------- */ template struct is_eigen_matrix : public std::false_type {}; template struct is_eigen_matrix< Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>> : public std::true_type {}; /* -------------------------------------------------------------------------- */ template struct is_eigen_matrix_base : public std::false_type {}; template struct is_eigen_matrix_base> : public std::true_type {}; } // namespace aka #define EIGEN_DEFAULT_DENSE_INDEX_TYPE akantu::Idx #define EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION Eigen::ColMajor #define EIGEN_DEFAULT_IO_FORMAT \ Eigen::IOFormat(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", \ "[", "]", "[", "]") /* -------------------------------------------------------------------------- */ #define EIGEN_MATRIXBASE_PLUGIN "aka_types_eigen_matrix_base_plugin.hh" #define EIGEN_MATRIX_PLUGIN "aka_types_eigen_matrix_plugin.hh" #define EIGEN_PLAINOBJECTBASE_PLUGIN \ "aka_types_eigen_plain_object_base_plugin.hh" #include #include /* -------------------------------------------------------------------------- */ namespace akantu { using Eigen::Ref; template using Vector = Eigen::Matrix; template using Matrix = Eigen::Matrix; template using VectorProxy = Eigen::Map::value, const Vector, n>, Vector, n>>>; template using MatrixProxy = Eigen::Map::value, const Matrix, m, n>, Matrix, m, n>>>; using VectorXr = Vector; using MatrixXr = Matrix; enum NormType : int8_t { L_1 = 1, L_2 = 2, L_inf = -1 }; struct TensorTraitBase {}; template struct TensorTrait : public TensorTraitBase {}; } // namespace akantu namespace aka { template using is_vector = aka::bool_constant< std::remove_reference_t>::IsVectorAtCompileTime>; template using is_matrix = aka::negation>; template using are_vectors = aka::conjunction...>; template using are_matrices = aka::conjunction...>; template using enable_if_matrices_t = std::enable_if_t::value>; template using enable_if_vectors_t = std::enable_if_t::value>; /* -------------------------------------------------------------------------- */ template struct is_tensor : public std::is_base_of {}; template struct is_tensor> : public std::true_type {}; template struct is_tensor> : public std::true_type {}; template struct is_tensor> : public std::true_type {}; template using is_tensor_n = std::is_base_of, T>; template using enable_if_tensors_n = std::enable_if< aka::conjunction< is_tensor_n..., std::is_same< std::common_type_t...>, std::decay_t>...>::value, T>; template using enable_if_tensors_n_t = typename enable_if_tensors_n::type; } // namespace aka namespace akantu { // fwd declaration template class TensorBase; template class TensorProxy; template class Tensor; } // namespace akantu /* -------------------------------------------------------------------------- */ #include "aka_view_iterators.hh" /* -------------------------------------------------------------------------- */ #include "aka_tensor.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class ArrayBase; /* -------------------------------------------------------------------------- */ namespace details { template struct MapPlainObjectType { using type = T; }; template struct MapPlainObjectType< Eigen::Map> { using type = PlainObjectType; }; template using MapPlainObjectType_t = typename MapPlainObjectType::type; template struct EigenMatrixViewHelper {}; template struct EigenMatrixViewHelper { using type = Eigen::Matrix; }; template struct EigenMatrixViewHelper { using type = Eigen::Matrix; }; template using EigenMatrixViewHelper_t = typename EigenMatrixViewHelper::type; template class EigenView { static_assert(sizeof...(sizes) == 1 or sizeof...(sizes) == 2, "Eigen only supports Vector and Matrices"); public: using size_type = typename std::decay_t::size_type; using value_type = typename std::decay_t::value_type; EigenView(Array && array, decltype(sizes)... sizes_) : array(array), sizes_(sizes_...) {} EigenView(Array && array) : array(array), sizes_(sizes...) {} EigenView(const EigenView & other) = default; EigenView(EigenView && other) noexcept = default; auto operator=(const EigenView & other) -> EigenView & = default; auto operator=(EigenView && other) noexcept -> EigenView & = default; template ().data())>, std::enable_if_t::value> * = nullptr> decltype(auto) begin() { return aka::make_from_tuple<::akantu::view_iterator< Eigen::Map>>>( std::tuple_cat(std::make_tuple(array.get().data()), sizes_)); } template ().data())>, std::enable_if_t::value> * = nullptr> decltype(auto) end() { return aka::make_from_tuple<::akantu::view_iterator< Eigen::Map>>>( std::tuple_cat(std::make_tuple(array.get().data() + array_size()), sizes_)); } decltype(auto) begin() const { return aka::make_from_tuple<::akantu::view_iterator< Eigen::Map>>>( std::tuple_cat(std::make_tuple(array.get().data()), sizes_)); } decltype(auto) end() const { return aka::make_from_tuple<::akantu::view_iterator< Eigen::Map>>>( std::tuple_cat(std::make_tuple(array.get().data() + array_size()), sizes_)); } private: template < class A = Array, std::enable_if_t>::value> * = nullptr> auto array_size() { return array.get().size() * array.get().getNbComponent(); } template >::value> * = nullptr> auto array_size() { return array.get().size(); } private: std::reference_wrapper> array; std::tuple sizes_; }; } // namespace details template decltype(auto) make_view(Array && array, Idx rows = RowsAtCompileTime) { return details::EigenView( std::forward(array), rows); } template decltype(auto) make_view(Array && array, Idx rows = RowsAtCompileTime, Idx cols = ColsAtCompileTime) { return details::EigenView( std::forward(array), rows, cols); } } // namespace akantu namespace Eigen { template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void MatrixBase::zero() { return this->fill(0.); } /* -------------------------------------------------------------------------- */ /* Vector */ /* -------------------------------------------------------------------------- */ template template ::value and ED::IsVectorAtCompileTime> *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::begin() { return ::akantu::view_iterator( this->derived().data()); } template template ::value and ED::IsVectorAtCompileTime> *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::end() { return ::akantu::view_iterator( this->derived().data() + this->size()); } template template *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::begin() const { using Scalar = typename Derived::Scalar; return ::akantu::const_view_iterator(this->derived().data()); } template template *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::end() const { using Scalar = typename Derived::Scalar; return ::akantu::const_view_iterator(this->derived().data() + this->size()); } /* -------------------------------------------------------------------------- */ /* Matrix */ /* -------------------------------------------------------------------------- */ template template ::value and not ED::IsVectorAtCompileTime> *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::begin() { return ::akantu::view_iterator< Map>>( this->derived().data(), this->rows()); } template template ::value and not ED::IsVectorAtCompileTime> *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::end() { return ::akantu::view_iterator< Map>>( this->derived().data() + this->size(), this->rows()); } template template *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::begin() const { using Scalar = typename Derived::Scalar; return ::akantu::const_view_iterator< Map>>( const_cast(this->derived().data()), this->rows()); } template template *> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) MatrixBase::end() const { using Scalar = typename Derived::Scalar; return ::akantu::const_view_iterator< Map>>( const_cast(this->derived().data()) + this->size(), this->rows()); } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void -MatrixBase::eig(const MatrixBase & values_) const { +MatrixBase::eig(MatrixBase & values) const { EigenSolver>> solver(*this, false); using OtherScalar = typename OtherDerived::Scalar; // as advised by the Eigen developers even though this is a UB - auto & values = const_cast &>(values_); + // auto & values = const_cast &>(values_); akantu::static_if(std::is_floating_point{}) .then([&](auto && solver) { values = solver.eigenvalues().real(); }) .else_([&](auto && solver) { values = solver.eigenvalues(); })( std::forward(solver)); } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void -MatrixBase::eig(const MatrixBase & values_, - const MatrixBase & vectors_, bool sort) const { +MatrixBase::eig(MatrixBase & values, MatrixBase & vectors, + bool sort) const { EigenSolver>> solver(*this, true); // as advised by the Eigen developers even though this is a UB - auto & values = const_cast &>(values_); - auto & vectors = const_cast &>(vectors_); + // auto & values = const_cast &>(values_); + // auto & vectors = const_cast &>(vectors_); auto norm = this->norm(); using OtherScalar = typename D1::Scalar; if ((solver.eigenvectors().imag().template lpNorm() > 1e-15 * norm) and std::is_floating_point::value) { AKANTU_EXCEPTION("This matrix has complex eigenvectors()"); } if (not sort) { akantu::static_if(std::is_floating_point{}) .then([&](auto && solver) { values = solver.eigenvalues().real(); vectors = solver.eigenvectors().real(); }) .else_([&](auto && solver) { values = solver.eigenvalues(); vectors = solver.eigenvectors(); })(std::forward(solver)); return; } if (not std::is_floating_point::value) { AKANTU_EXCEPTION("Cannot sort complex eigen values"); } values = solver.eigenvalues().real(); PermutationMatrix P(values.size()); P.setIdentity(); std::sort(P.indices().data(), P.indices().data() + P.indices().size(), [&values](const Index & a, const Index & b) { return (values(a) - values(b)) > 0; }); akantu::static_if(std::is_floating_point{}) .then([&](auto && solver) { values = P.transpose() * values; vectors = solver.eigenvectors().real() * P; })(std::forward(solver)); return; } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void MatrixBase::eigh(const MatrixBase & values_) const { SelfAdjointEigenSolver< akantu::details::MapPlainObjectType_t>> solver(*this, EigenvaluesOnly); // as advised by the Eigen developers even though this is a UB auto & values = const_cast &>(values_); values = solver.eigenvalues(); } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void MatrixBase::eigh(const MatrixBase & values_, const MatrixBase & vectors_, bool sort) const { SelfAdjointEigenSolver< akantu::details::MapPlainObjectType_t>> solver(*this, ComputeEigenvectors); // as advised by the Eigen developers, even though this is a UB auto & values = const_cast &>(values_); auto & vectors = const_cast &>(vectors_); if (not sort) { values = solver.eigenvalues(); vectors = solver.eigenvectors(); return; } values = solver.eigenvalues(); PermutationMatrix P(values.size()); P.setIdentity(); std::sort(P.indices().data(), P.indices().data() + P.indices().size(), [&values](const Index & a, const Index & b) { return (values(a) - values(b)) > 0; }); values = P.transpose() * values(); vectors = solver.eigenvectors() * P; } } // namespace Eigen namespace std { template struct is_convertible, Eigen::Map> : aka::bool_constant::value> {}; } // namespace std #endif /* AKANTU_AKA_TYPES_HH */ diff --git a/src/common/aka_types_eigen_matrix_base_plugin.hh b/src/common/aka_types_eigen_matrix_base_plugin.hh index 430b75f43..4ed4318fa 100644 --- a/src/common/aka_types_eigen_matrix_base_plugin.hh +++ b/src/common/aka_types_eigen_matrix_base_plugin.hh @@ -1,168 +1,168 @@ using size_type = Index; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void zero(); template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) operator()(Index c) { auto & d = this->derived(); return d.col(c); } template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) operator()(Index c) const { const auto & d = this->derived(); return d.col(c); } template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) operator()(Index c) { return Base::operator()(c); } template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) operator()(Index c) const { return Base::operator()(c); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) operator()(Index i, Index j) { return Base::operator()(i, j); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) operator()(Index i, Index j) const { return Base::operator()(i, j); } template < typename ED = Derived, typename T = std::remove_reference_t().data())>, std::enable_if_t::value and ED::IsVectorAtCompileTime> * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) begin(); template < typename ED = Derived, typename T = std::remove_reference_t().data())>, std::enable_if_t::value and ED::IsVectorAtCompileTime> * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) end(); template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) begin() const; template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) end() const; template < typename ED = Derived, typename T = std::remove_reference_t().data())>, std::enable_if_t::value and not ED::IsVectorAtCompileTime> * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) begin(); template < typename ED = Derived, typename T = std::remove_reference_t().data())>, std::enable_if_t::value and not ED::IsVectorAtCompileTime> * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) end(); template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) begin() const; template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE decltype(auto) end() const; // clang-format off [[deprecated("use data instead to be stl compatible")]] Scalar * storage() { return this->data(); } [[deprecated("use data instead to be stl compatible")]] const Scalar * storage() const { return this->data(); } // clang-format on EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return this->rows() * this->cols(); } template * = nullptr> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size(Index i) const { AKANTU_DEBUG_ASSERT(i < 2, "This tensor has only " << 2 << " dimensions, not " << (i + 1)); return (i == 0) ? this->rows() : this->cols(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void set(const Scalar & t) { this->fill(t); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void eye(const Scalar & t = Scalar()) { (*this) = t * Matrix::Identity(this->rows(), this->cols()); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void clear() { this->fill(Scalar()); }; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE auto distance(const MatrixBase & other) const { return (*this - other).norm(); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar doubleDot(const MatrixBase & other) const { eigen_assert(rows() == cols() and rows() == other.rows() and cols() == other.cols()); return this->cwiseProduct(other).sum(); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void -eig(const MatrixBase & other) const; +eig(MatrixBase & other) const; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void -eig(const MatrixBase & values, const MatrixBase & vectors, +eig(MatrixBase & values, MatrixBase & vectors, bool sort = std::is_floating_point::value) const; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void eigh(const MatrixBase & other) const; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void eigh(const MatrixBase & values, const MatrixBase & vectors, bool sort = true) const; template inline bool operator<=(const MatrixBase & v) const { return this->isMuchSmallerThan(v); } template inline bool operator>=(const MatrixBase & v) const { return v.isMuchSmallerThan(*this); } template inline bool operator<(const MatrixBase & v) const { return (*this <= v) and (*this != v); } template inline bool operator>(const MatrixBase & v) const { return (*this >= v) and (*this != v); } diff --git a/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.hh b/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.hh index a1f985144..397a237de 100644 --- a/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_hexahedron_20_inline_impl.hh @@ -1,231 +1,232 @@ /** * @file element_class_hexahedron_20_inline_impl.hh * * @author Guillaume Anciaux * @author Mauro Corrado * @author Sacha Laffely * @author Nicolas Richart * @author Damien Scantamburlo * * @date creation: Tue Mar 31 2015 * @date last modification: Fri Feb 07 2020 * * @brief Specialization of the element_class class for the type _hexahedron_20 * * * @section LICENSE * * Copyright (©) 2015-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim \y \z / | / 7-----|18--------6 /| | / /| / | | / / | 19 | | / 17 | / 15 | / / 14 / | | / / | 4-------16---/---5 | | | +----|------------\x | 3-------10-|-----2 | / | / 12 / 13 / | 11 | 9 | / | / |/ |/ 0--------8-------1 x y z * N0 -1 -1 -1 * N1 1 -1 -1 * N2 1 1 -1 * N3 -1 1 -1 * N4 -1 -1 1 * N5 1 -1 1 * N6 1 1 1 * N7 -1 1 1 * N8 0 -1 -1 * N9 1 0 -1 * N10 0 1 -1 * N11 -1 0 -1 * N12 -1 -1 0 * N13 1 -1 0 * N14 1 1 0 * N15 -1 1 0 * N16 0 -1 1 * N17 1 0 1 * N18 0 1 1 * N19 -1 0 1 * \endverbatim */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_hexahedron_20, _gt_hexahedron_20, _itp_serendip_hexahedron_20, _ek_regular, 3, _git_segment, 3); /* -------------------------------------------------------------------------- */ template <> -template::value> *> +template ::value> *> inline void InterpolationElement<_itp_serendip_hexahedron_20>::computeShapes( const Eigen::MatrixBase & c, Eigen::MatrixBase & N) { // Shape function , Natural coordinates N(0) = 0.125 * (1 - c(0)) * (1 - c(1)) * (1 - c(2)) * (-2 - c(0) - c(1) - c(2)); N(1) = 0.125 * (1 + c(0)) * (1 - c(1)) * (1 - c(2)) * (-2 + c(0) - c(1) - c(2)); N(2) = 0.125 * (1 + c(0)) * (1 + c(1)) * (1 - c(2)) * (-2 + c(0) + c(1) - c(2)); N(3) = 0.125 * (1 - c(0)) * (1 + c(1)) * (1 - c(2)) * (-2 - c(0) + c(1) - c(2)); N(4) = 0.125 * (1 - c(0)) * (1 - c(1)) * (1 + c(2)) * (-2 - c(0) - c(1) + c(2)); N(5) = 0.125 * (1 + c(0)) * (1 - c(1)) * (1 + c(2)) * (-2 + c(0) - c(1) + c(2)); N(6) = 0.125 * (1 + c(0)) * (1 + c(1)) * (1 + c(2)) * (-2 + c(0) + c(1) + c(2)); N(7) = 0.125 * (1 - c(0)) * (1 + c(1)) * (1 + c(2)) * (-2 - c(0) + c(1) + c(2)); N(8) = 0.25 * (1 - c(0) * c(0)) * (1 - c(1)) * (1 - c(2)); N(9) = 0.25 * (1 - c(1) * c(1)) * (1 + c(0)) * (1 - c(2)); N(10) = 0.25 * (1 - c(0) * c(0)) * (1 + c(1)) * (1 - c(2)); N(11) = 0.25 * (1 - c(1) * c(1)) * (1 - c(0)) * (1 - c(2)); N(12) = 0.25 * (1 - c(2) * c(2)) * (1 - c(0)) * (1 - c(1)); N(13) = 0.25 * (1 - c(2) * c(2)) * (1 + c(0)) * (1 - c(1)); N(14) = 0.25 * (1 - c(2) * c(2)) * (1 + c(0)) * (1 + c(1)); N(15) = 0.25 * (1 - c(2) * c(2)) * (1 - c(0)) * (1 + c(1)); N(16) = 0.25 * (1 - c(0) * c(0)) * (1 - c(1)) * (1 + c(2)); N(17) = 0.25 * (1 - c(1) * c(1)) * (1 + c(0)) * (1 + c(2)); N(18) = 0.25 * (1 - c(0) * c(0)) * (1 + c(1)) * (1 + c(2)); N(19) = 0.25 * (1 - c(1) * c(1)) * (1 - c(0)) * (1 + c(2)); } /* -------------------------------------------------------------------------- */ template <> -template +template inline void InterpolationElement<_itp_serendip_hexahedron_20>::computeDNDS( const Eigen::MatrixBase & c, Eigen::MatrixBase & dnds) { // derivatives ddx dnds(0, 0) = 0.25 * (c(0) + 0.5 * (c(1) + c(2) + 1)) * (c(1) - 1) * (c(2) - 1); dnds(0, 1) = 0.25 * (c(0) - 0.5 * (c(1) + c(2) + 1)) * (c(1) - 1) * (c(2) - 1); dnds(0, 2) = -0.25 * (c(0) + 0.5 * (c(1) - c(2) - 1)) * (c(1) + 1) * (c(2) - 1); dnds(0, 3) = -0.25 * (c(0) - 0.5 * (c(1) - c(2) - 1)) * (c(1) + 1) * (c(2) - 1); dnds(0, 4) = -0.25 * (c(0) + 0.5 * (c(1) - c(2) + 1)) * (c(1) - 1) * (c(2) + 1); dnds(0, 5) = -0.25 * (c(0) - 0.5 * (c(1) - c(2) + 1)) * (c(1) - 1) * (c(2) + 1); dnds(0, 6) = 0.25 * (c(0) + 0.5 * (c(1) + c(2) - 1)) * (c(1) + 1) * (c(2) + 1); dnds(0, 7) = 0.25 * (c(0) - 0.5 * (c(1) + c(2) - 1)) * (c(1) + 1) * (c(2) + 1); dnds(0, 8) = -0.5 * c(0) * (c(1) - 1) * (c(2) - 1); dnds(0, 9) = 0.25 * (c(1) * c(1) - 1) * (c(2) - 1); dnds(0, 10) = 0.5 * c(0) * (c(1) + 1) * (c(2) - 1); dnds(0, 11) = -0.25 * (c(1) * c(1) - 1) * (c(2) - 1); dnds(0, 12) = -0.25 * (c(2) * c(2) - 1) * (c(1) - 1); dnds(0, 13) = 0.25 * (c(1) - 1) * (c(2) * c(2) - 1); dnds(0, 14) = -0.25 * (c(1) + 1) * (c(2) * c(2) - 1); dnds(0, 15) = 0.25 * (c(1) + 1) * (c(2) * c(2) - 1); dnds(0, 16) = 0.5 * c(0) * (c(1) - 1) * (c(2) + 1); dnds(0, 17) = -0.25 * (c(2) + 1) * (c(1) * c(1) - 1); dnds(0, 18) = -0.5 * c(0) * (c(1) + 1) * (c(2) + 1); dnds(0, 19) = 0.25 * (c(2) + 1) * (c(1) * c(1) - 1); // ddy dnds(1, 0) = 0.25 * (c(1) + 0.5 * (c(0) + c(2) + 1)) * (c(0) - 1) * (c(2) - 1); dnds(1, 1) = -0.25 * (c(1) - 0.5 * (c(0) - c(2) - 1)) * (c(0) + 1) * (c(2) - 1); dnds(1, 2) = -0.25 * (c(1) + 0.5 * (c(0) - c(2) - 1)) * (c(0) + 1) * (c(2) - 1); dnds(1, 3) = 0.25 * (c(1) - 0.5 * (c(0) + c(2) + 1)) * (c(0) - 1) * (c(2) - 1); dnds(1, 4) = -0.25 * (c(1) + 0.5 * (c(0) - c(2) + 1)) * (c(0) - 1) * (c(2) + 1); dnds(1, 5) = 0.25 * (c(1) - 0.5 * (c(0) + c(2) - 1)) * (c(0) + 1) * (c(2) + 1); dnds(1, 6) = 0.25 * (c(1) + 0.5 * (c(0) + c(2) - 1)) * (c(0) + 1) * (c(2) + 1); dnds(1, 7) = -0.25 * (c(1) - 0.5 * (c(0) - c(2) + 1)) * (c(0) - 1) * (c(2) + 1); dnds(1, 8) = -0.25 * (c(0) * c(0) - 1) * (c(2) - 1); dnds(1, 9) = 0.5 * c(1) * (c(0) + 1) * (c(2) - 1); dnds(1, 10) = 0.25 * (c(0) * c(0) - 1) * (c(2) - 1); dnds(1, 11) = -0.5 * c(1) * (c(0) - 1) * (c(2) - 1); dnds(1, 12) = -0.25 * (c(2) * c(2) - 1) * (c(0) - 1); dnds(1, 13) = 0.25 * (c(0) + 1) * (c(2) * c(2) - 1); dnds(1, 14) = -0.25 * (c(0) + 1) * (c(2) * c(2) - 1); dnds(1, 15) = 0.25 * (c(0) - 1) * (c(2) * c(2) - 1); dnds(1, 16) = 0.25 * (c(2) + 1) * (c(0) * c(0) - 1); dnds(1, 17) = -0.5 * c(1) * (c(0) + 1) * (c(2) + 1); dnds(1, 18) = -0.25 * (c(2) + 1) * (c(0) * c(0) - 1); dnds(1, 19) = 0.5 * c(1) * (c(0) - 1) * (c(2) + 1); // ddz dnds(2, 0) = 0.25 * (c(2) + 0.5 * (c(0) + c(1) + 1)) * (c(0) - 1) * (c(1) - 1); dnds(2, 1) = -0.25 * (c(2) - 0.5 * (c(0) - c(1) - 1)) * (c(0) + 1) * (c(1) - 1); dnds(2, 2) = 0.25 * (c(2) - 0.5 * (c(0) + c(1) - 1)) * (c(0) + 1) * (c(1) + 1); dnds(2, 3) = -0.25 * (c(2) + 0.5 * (c(0) - c(1) + 1)) * (c(0) - 1) * (c(1) + 1); dnds(2, 4) = 0.25 * (c(2) - 0.5 * (c(0) + c(1) + 1)) * (c(0) - 1) * (c(1) - 1); dnds(2, 5) = -0.25 * (c(2) + 0.5 * (c(0) - c(1) - 1)) * (c(0) + 1) * (c(1) - 1); dnds(2, 6) = 0.25 * (c(2) + 0.5 * (c(0) + c(1) - 1)) * (c(0) + 1) * (c(1) + 1); dnds(2, 7) = -0.25 * (c(2) - 0.5 * (c(0) - c(1) + 1)) * (c(0) - 1) * (c(1) + 1); dnds(2, 8) = -0.25 * (c(0) * c(0) - 1) * (c(1) - 1); dnds(2, 9) = 0.25 * (c(1) * c(1) - 1) * (c(0) + 1); dnds(2, 10) = 0.25 * (c(0) * c(0) - 1) * (c(1) + 1); dnds(2, 11) = -0.25 * (c(1) * c(1) - 1) * (c(0) - 1); dnds(2, 12) = -0.5 * c(2) * (c(1) - 1) * (c(0) - 1); dnds(2, 13) = 0.5 * c(2) * (c(0) + 1) * (c(1) - 1); dnds(2, 14) = -0.5 * c(2) * (c(0) + 1) * (c(1) + 1); dnds(2, 15) = 0.5 * c(2) * (c(0) - 1) * (c(1) + 1); dnds(2, 16) = 0.25 * (c(1) - 1) * (c(0) * c(0) - 1); dnds(2, 17) = -0.25 * (c(0) + 1) * (c(1) * c(1) - 1); dnds(2, 18) = -0.25 * (c(1) + 1) * (c(0) * c(0) - 1); dnds(2, 19) = 0.25 * (c(0) - 1) * (c(1) * c(1) - 1); } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_hexahedron_20>::getInradius( +constexpr inline Real GeometricalElement<_gt_hexahedron_20>::getInradius( const Eigen::MatrixBase & coord) { return GeometricalElement<_gt_hexahedron_8>::getInradius(coord) * 0.5; } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.hh b/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.hh index 91306176f..464d3b88a 100644 --- a/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_hexahedron_8_inline_impl.hh @@ -1,225 +1,226 @@ /** * @file element_class_hexahedron_8_inline_impl.hh * * @author Guillaume Anciaux * @author Nicolas Richart * @author Peter Spijker * * @date creation: Mon Mar 14 2011 * @date last modification: Fri Feb 07 2020 * * @brief Specialization of the element_class class for the type _hexahedron_8 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim \zeta ^ (-1,1,1) | (1,1,1) 7---|------6 /| | /| / | | / | (-1,-1,1) 4----------5 | (1,-1,1) | | | | | | | | | | | | +---|-------> \xi | | / | | (-1,1,-1) | 3-/-----|--2 (1,1,-1) | / / | / |/ / |/ 0-/--------1 (-1,-1,-1) / (1,-1,-1) / \eta @endverbatim * * \f[ * \begin{array}{llll} * N1 = (1 - \xi) (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N1}{\partial \xi} = - (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N1}{\partial \eta} = - (1 - \xi) (1 - \zeta) / 8 * & \frac{\partial N1}{\partial \zeta} = - (1 - \xi) (1 - \eta) / 8 \\ * N2 = (1 + \xi) (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N2}{\partial \xi} = (1 - \eta) (1 - \zeta) / 8 * & \frac{\partial N2}{\partial \eta} = - (1 + \xi) (1 - \zeta) / 8 * & \frac{\partial N2}{\partial \zeta} = - (1 + \xi) (1 - \eta) / 8 \\ * N3 = (1 + \xi) (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N3}{\partial \xi} = (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N3}{\partial \eta} = (1 + \xi) (1 - \zeta) / 8 * & \frac{\partial N3}{\partial \zeta} = - (1 + \xi) (1 + \eta) / 8 \\ * N4 = (1 - \xi) (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N4}{\partial \xi} = - (1 + \eta) (1 - \zeta) / 8 * & \frac{\partial N4}{\partial \eta} = (1 - \xi) (1 - \zeta) / 8 * & \frac{\partial N4}{\partial \zeta} = - (1 - \xi) (1 + \eta) / 8 \\ * N5 = (1 - \xi) (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N5}{\partial \xi} = - (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N5}{\partial \eta} = - (1 - \xi) (1 + \zeta) / 8 * & \frac{\partial N5}{\partial \zeta} = (1 - \xi) (1 - \eta) / 8 \\ * N6 = (1 + \xi) (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N6}{\partial \xi} = (1 - \eta) (1 + \zeta) / 8 * & \frac{\partial N6}{\partial \eta} = - (1 + \xi) (1 + \zeta) / 8 * & \frac{\partial N6}{\partial \zeta} = (1 + \xi) (1 - \eta) / 8 \\ * N7 = (1 + \xi) (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N7}{\partial \xi} = (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N7}{\partial \eta} = (1 + \xi) (1 + \zeta) / 8 * & \frac{\partial N7}{\partial \zeta} = (1 + \xi) (1 + \eta) / 8 \\ * N8 = (1 - \xi) (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N8}{\partial \xi} = - (1 + \eta) (1 + \zeta) / 8 * & \frac{\partial N8}{\partial \eta} = (1 - \xi) (1 + \zeta) / 8 * & \frac{\partial N8}{\partial \zeta} = (1 - \xi) (1 + \eta) / 8 \\ * \end{array} * \f] * * @f{eqnarray*}{ * \xi_{q0} &=& -1/\sqrt{3} \qquad \eta_{q0} = -1/\sqrt{3} \qquad \zeta_{q0} = -1/\sqrt{3} \\ * \xi_{q1} &=& 1/\sqrt{3} \qquad \eta_{q1} = -1/\sqrt{3} \qquad \zeta_{q1} = -1/\sqrt{3} \\ * \xi_{q2} &=& 1/\sqrt{3} \qquad \eta_{q2} = 1/\sqrt{3} \qquad \zeta_{q2} = -1/\sqrt{3} \\ * \xi_{q3} &=& -1/\sqrt{3} \qquad \eta_{q3} = 1/\sqrt{3} \qquad \zeta_{q3} = -1/\sqrt{3} \\ * \xi_{q4} &=& -1/\sqrt{3} \qquad \eta_{q4} = -1/\sqrt{3} \qquad \zeta_{q4} = 1/\sqrt{3} \\ * \xi_{q5} &=& 1/\sqrt{3} \qquad \eta_{q5} = -1/\sqrt{3} \qquad \zeta_{q5} = 1/\sqrt{3} \\ * \xi_{q6} &=& 1/\sqrt{3} \qquad \eta_{q6} = 1/\sqrt{3} \qquad \zeta_{q6} = 1/\sqrt{3} \\ * \xi_{q7} &=& -1/\sqrt{3} \qquad \eta_{q7} = 1/\sqrt{3} \qquad \zeta_{q7} = 1/\sqrt{3} \\ * @f} */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_hexahedron_8, _gt_hexahedron_8, _itp_lagrange_hexahedron_8, _ek_regular, 3, _git_segment, 2); /* -------------------------------------------------------------------------- */ template <> -template ::value> *> +template ::value> *> inline void InterpolationElement<_itp_lagrange_hexahedron_8>::computeShapes( const Eigen::MatrixBase & c, Eigen::MatrixBase & N) { /// Natural coordinates N(0) = .125 * (1 - c(0)) * (1 - c(1)) * (1 - c(2)); /// N1(q_0) N(1) = .125 * (1 + c(0)) * (1 - c(1)) * (1 - c(2)); /// N2(q_0) N(2) = .125 * (1 + c(0)) * (1 + c(1)) * (1 - c(2)); /// N3(q_0) N(3) = .125 * (1 - c(0)) * (1 + c(1)) * (1 - c(2)); /// N4(q_0) N(4) = .125 * (1 - c(0)) * (1 - c(1)) * (1 + c(2)); /// N5(q_0) N(5) = .125 * (1 + c(0)) * (1 - c(1)) * (1 + c(2)); /// N6(q_0) N(6) = .125 * (1 + c(0)) * (1 + c(1)) * (1 + c(2)); /// N7(q_0) N(7) = .125 * (1 - c(0)) * (1 + c(1)) * (1 + c(2)); /// N8(q_0) } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_hexahedron_8>::computeDNDS( const Eigen::MatrixBase & c, Eigen::MatrixBase & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial * N4}{\partial \xi} * & \frac{\partial N5}{\partial \xi} & \frac{\partial * N6}{\partial \xi} * & \frac{\partial N7}{\partial \xi} & \frac{\partial * N8}{\partial \xi}\\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial * N4}{\partial \eta} * & \frac{\partial N5}{\partial \eta} & \frac{\partial * N6}{\partial \eta} * & \frac{\partial N7}{\partial \eta} & \frac{\partial * N8}{\partial \eta}\\ * \frac{\partial N1}{\partial \zeta} & \frac{\partial N2}{\partial * \zeta} * & \frac{\partial N3}{\partial \zeta} & \frac{\partial * N4}{\partial \zeta} * & \frac{\partial N5}{\partial \zeta} & \frac{\partial * N6}{\partial \zeta} * & \frac{\partial N7}{\partial \zeta} & \frac{\partial * N8}{\partial \zeta} * \end{array} * \right) * @f] */ dnds(0, 0) = -.125 * (1 - c(1)) * (1 - c(2)); dnds(0, 1) = .125 * (1 - c(1)) * (1 - c(2)); dnds(0, 2) = .125 * (1 + c(1)) * (1 - c(2)); dnds(0, 3) = -.125 * (1 + c(1)) * (1 - c(2)); dnds(0, 4) = -.125 * (1 - c(1)) * (1 + c(2)); dnds(0, 5) = .125 * (1 - c(1)) * (1 + c(2)); dnds(0, 6) = .125 * (1 + c(1)) * (1 + c(2)); dnds(0, 7) = -.125 * (1 + c(1)) * (1 + c(2)); dnds(1, 0) = -.125 * (1 - c(0)) * (1 - c(2)); dnds(1, 1) = -.125 * (1 + c(0)) * (1 - c(2)); dnds(1, 2) = .125 * (1 + c(0)) * (1 - c(2)); dnds(1, 3) = .125 * (1 - c(0)) * (1 - c(2)); dnds(1, 4) = -.125 * (1 - c(0)) * (1 + c(2)); dnds(1, 5) = -.125 * (1 + c(0)) * (1 + c(2)); dnds(1, 6) = .125 * (1 + c(0)) * (1 + c(2)); dnds(1, 7) = .125 * (1 - c(0)) * (1 + c(2)); dnds(2, 0) = -.125 * (1 - c(0)) * (1 - c(1)); dnds(2, 1) = -.125 * (1 + c(0)) * (1 - c(1)); dnds(2, 2) = -.125 * (1 + c(0)) * (1 + c(1)); dnds(2, 3) = -.125 * (1 - c(0)) * (1 + c(1)); dnds(2, 4) = .125 * (1 - c(0)) * (1 - c(1)); dnds(2, 5) = .125 * (1 + c(0)) * (1 - c(1)); dnds(2, 6) = .125 * (1 + c(0)) * (1 + c(1)); dnds(2, 7) = .125 * (1 - c(0)) * (1 + c(1)); } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_hexahedron_8>::getInradius( +constexpr inline Real GeometricalElement<_gt_hexahedron_8>::getInradius( const Eigen::MatrixBase & X) { auto && a = (X(0) - X(1)).norm(); auto && b = (X(1) - X(2)).norm(); auto && c = (X(2) - X(3)).norm(); auto && d = (X(3) - X(0)).norm(); auto && e = (X(0) - X(4)).norm(); auto && f = (X(1) - X(5)).norm(); auto && g = (X(2) - X(6)).norm(); auto && h = (X(3) - X(7)).norm(); auto && i = (X(4) - X(5)).norm(); auto && j = (X(5) - X(6)).norm(); auto && k = (X(6) - X(7)).norm(); auto && l = (X(7) - X(4)).norm(); auto p = std::min({a, b, c, d, e, f, g, h, i, j, k, l}); return p; } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.hh b/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.hh index f378e7981..47ea2452c 100644 --- a/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_pentahedron_15_inline_impl.hh @@ -1,186 +1,186 @@ /** * @file element_class_pentahedron_15_inline_impl.hh * * @author Guillaume Anciaux * @author Mauro Corrado * @author Sacha Laffely * @author Nicolas Richart * @author Damien Scantamburlo * * @date creation: Tue Mar 31 2015 * @date last modification: Fri Feb 07 2020 * * @brief Specialization of the element_class class for the type * _pentahedron_15 * * * @section LICENSE * * Copyright (©) 2015-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * \verbatim z ^ | | | 1 | /|\ |/ | \ 10 7 6 / | \ / | \ 4 2--8--0 | \ / / | \11 / 13 12 9---------->y | / \ / |/ \ / 5--14--3 / / / v x \endverbatim x y z * N0 -1 1 0 * N1 -1 0 1 * N2 -1 0 0 * N3 1 1 0 * N4 1 0 1 * N5 1 0 0 * N6 -1 0.5 0.5 * N7 -1 0 0.5 * N8 -1 0.5 0 * N9 0 1 0 * N10 0 0 1 * N11 0 0 0 * N12 1 0.5 0.5 * N13 1 0 0.5 * N14 1 0.5 0 */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_pentahedron_15, _gt_pentahedron_15, _itp_lagrange_pentahedron_15, _ek_regular, 3, _git_pentahedron, 2); /* -------------------------------------------------------------------------- */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_pentahedron_15>::computeShapes( const Eigen::MatrixBase & c, Eigen::MatrixBase & N) { auto && x = c(0); auto && y = c(1); auto && z = c(2); // Shape Functions, Natural coordinates N(0) = 0.5 * y * (1 - x) * (2 * y - 2 - x); N(1) = 0.5 * z * (1 - x) * (2 * z - 2 - x); N(2) = 0.5 * (x - 1) * (1 - y - z) * (x + 2 * y + 2 * z); N(3) = 0.5 * y * (1 + x) * (2 * y - 2 + x); N(4) = 0.5 * z * (1 + x) * (2 * z - 2 + x); N(5) = 0.5 * (-x - 1) * (1 - y - z) * (-x + 2 * y + 2 * z); N(6) = 2.0 * y * z * (1 - x); N(7) = 2.0 * z * (1 - y - z) * (1 - x); N(8) = 2.0 * y * (1 - x) * (1 - y - z); N(9) = y * (1 - x * x); N(10) = z * (1 - x * x); N(11) = (1 - y - z) * (1 - x * x); N(12) = 2.0 * y * z * (1 + x); N(13) = 2.0 * z * (1 - y - z) * (1 + x); N(14) = 2.0 * y * (1 - y - z) * (1 + x); } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_pentahedron_15>::computeDNDS( const Eigen::MatrixBase & c, Eigen::MatrixBase & dnds) { auto && x = c(0); auto && y = c(1); auto && z = c(2); // ddx dnds(0, 0) = 0.5 * y * (2 * x - 2 * y + 1); dnds(0, 1) = 0.5 * z * (2 * x - 2 * z + 1); dnds(0, 2) = -0.5 * (2 * x + 2 * y + 2 * z - 1) * (y + z - 1); dnds(0, 3) = 0.5 * y * (2 * x + 2 * y - 1); dnds(0, 4) = 0.5 * z * (2 * x + 2 * z - 1); dnds(0, 5) = -0.5 * (y + z - 1) * (2 * x - 2 * y - 2 * z + 1); dnds(0, 6) = -2.0 * y * z; dnds(0, 7) = 2.0 * z * (y + z - 1); dnds(0, 8) = 2.0 * y * (y + z - 1); dnds(0, 9) = -2.0 * x * y; dnds(0, 10) = -2.0 * x * z; dnds(0, 11) = 2.0 * x * (y + z - 1); dnds(0, 12) = 2.0 * y * z; dnds(0, 13) = -2.0 * z * (y + z - 1); dnds(0, 14) = -2.0 * y * (y + z - 1); // ddy dnds(1, 0) = -0.5 * (x - 1) * (4 * y - x - 2); dnds(1, 1) = 0.0; dnds(1, 2) = -0.5 * (x - 1) * (4 * y + x + 2 * (2 * z - 1)); dnds(1, 3) = 0.5 * (x + 1) * (4 * y + x - 2); dnds(1, 4) = 0.0; dnds(1, 5) = 0.5 * (x + 1) * (4 * y - x + 2 * (2 * z - 1)); dnds(1, 6) = -2.0 * (x - 1) * z; dnds(1, 7) = 2.0 * z * (x - 1); dnds(1, 8) = 2.0 * (2 * y + z - 1) * (x - 1); dnds(1, 9) = -(x * x - 1); dnds(1, 10) = 0.0; dnds(1, 11) = (x * x - 1); dnds(1, 12) = 2.0 * z * (x + 1); dnds(1, 13) = -2.0 * z * (x + 1); dnds(1, 14) = -2.0 * (2 * y + z - 1) * (x + 1); // ddz dnds(2, 0) = 0.0; dnds(2, 1) = -0.5 * (x - 1) * (4 * z - x - 2); dnds(2, 2) = -0.5 * (x - 1) * (4 * z + x + 2 * (2 * y - 1)); dnds(2, 3) = 0.0; dnds(2, 4) = 0.5 * (x + 1) * (4 * z + x - 2); dnds(2, 5) = 0.5 * (x + 1) * (4 * z - x + 2 * (2 * y - 1)); dnds(2, 6) = -2.0 * (x - 1) * y; dnds(2, 7) = 2.0 * (x - 1) * (2 * z + y - 1); dnds(2, 8) = 2.0 * y * (x - 1); dnds(2, 9) = 0.0; dnds(2, 10) = -(x * x - 1); dnds(2, 11) = (x * x - 1); dnds(2, 12) = 2.0 * (x + 1) * y; dnds(2, 13) = -2.0 * (x + 1) * (2 * z + y - 1); dnds(2, 14) = -2.0 * (x + 1) * y; } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_pentahedron_15>::getInradius( +constexpr inline Real GeometricalElement<_gt_pentahedron_15>::getInradius( const Eigen::MatrixBase & coord) { return GeometricalElement<_gt_pentahedron_6>::getInradius(coord) * 0.5; } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.hh b/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.hh index f31ce99d1..93cf4ef2e 100644 --- a/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_pentahedron_6_inline_impl.hh @@ -1,142 +1,142 @@ /** * @file element_class_pentahedron_6_inline_impl.hh * * @author Guillaume Anciaux * @author Marion Estelle Chambart * @author Mauro Corrado * @author Thomas Menouillard * @author Nicolas Richart * * @date creation: Mon Mar 14 2011 * @date last modification: Tue Sep 29 2020 * * @brief Specialization of the element_class class for the type _pentahedron_6 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim /z | | | 1 | /|\ |/ | \ / | \ / | \ / | \ 4 2-----0 | \ / / | \/ / | \ /----------/y | / \ / |/ \ / 5---.--3 / / / \x x y z * N0 -1 1 0 * N1 -1 0 1 * N2 -1 0 0 * N3 1 1 0 * N4 1 0 1 * N5 1 0 0 \endverbatim */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_pentahedron_6, _gt_pentahedron_6, _itp_lagrange_pentahedron_6, _ek_regular, 3, _git_pentahedron, 1); /* -------------------------------------------------------------------------- */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_pentahedron_6>::computeShapes( const Eigen::MatrixBase & c, Eigen::MatrixBase & N) { /// Natural coordinates N(0) = 0.5 * c(1) * (1 - c(0)); // N1(q) N(1) = 0.5 * c(2) * (1 - c(0)); // N2(q) N(2) = 0.5 * (1 - c(1) - c(2)) * (1 - c(0)); // N3(q) N(3) = 0.5 * c(1) * (1 + c(0)); // N4(q) N(4) = 0.5 * c(2) * (1 + c(0)); // N5(q) N(5) = 0.5 * (1 - c(1) - c(2)) * (1 + c(0)); // N6(q) } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_pentahedron_6>::computeDNDS( const Eigen::MatrixBase & c, Eigen::MatrixBase & dnds) { dnds(0, 0) = -0.5 * c(1); dnds(0, 1) = -0.5 * c(2); dnds(0, 2) = -0.5 * (1 - c(1) - c(2)); dnds(0, 3) = 0.5 * c(1); dnds(0, 4) = 0.5 * c(2); dnds(0, 5) = 0.5 * (1 - c(1) - c(2)); dnds(1, 0) = 0.5 * (1 - c(0)); dnds(1, 1) = 0.0; dnds(1, 2) = -0.5 * (1 - c(0)); dnds(1, 3) = 0.5 * (1 + c(0)); dnds(1, 4) = 0.0; dnds(1, 5) = -0.5 * (1 + c(0)); dnds(2, 0) = 0.0; dnds(2, 1) = 0.5 * (1 - c(0)); dnds(2, 2) = -0.5 * (1 - c(0)); dnds(2, 3) = 0.0; dnds(2, 4) = 0.5 * (1 + c(0)); dnds(2, 5) = -0.5 * (1 + c(0)); } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_pentahedron_6>::getInradius( +constexpr inline Real GeometricalElement<_gt_pentahedron_6>::getInradius( const Eigen::MatrixBase & coord) { auto && u0 = coord.col(0); auto && u1 = coord.col(1); auto && u2 = coord.col(2); auto && u3 = coord.col(3); auto && u4 = coord.col(4); auto && u5 = coord.col(5); auto inradius_triangle_1 = Math::triangle_inradius(u0, u1, u2); auto inradius_triangle_2 = Math::triangle_inradius(u3, u4, u5); auto d1 = (u3 - u0).norm() * 0.5; auto d2 = (u5 - u2).norm() * 0.5; auto d3 = (u4 - u1).norm() * 0.5; auto p = 2. * std::min({inradius_triangle_1, inradius_triangle_2, d1, d2, d3}); return p; } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_point_1_inline_impl.hh b/src/fe_engine/element_classes/element_class_point_1_inline_impl.hh index 497ef1039..998143563 100644 --- a/src/fe_engine/element_classes/element_class_point_1_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_point_1_inline_impl.hh @@ -1,95 +1,96 @@ /** * @file element_class_point_1_inline_impl.hh * * @author Dana Christen * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Feb 28 2020 * * @brief Specialization of the element_class class for the type _point_1 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim x (0) @endverbatim * * @f{eqnarray*}{ * N1 &=& 1 * @f} * * @f{eqnarray*}{ * q_0 &=& 0 * @f} */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_point_1, _gt_point, _itp_lagrange_point_1, _ek_regular, 0, _git_point, 1); -template<> +template <> template -inline void ElementClass<_point_1, _ek_regular>::computeNormalsOnNaturalCoordinates( -const Eigen::MatrixBase & /*coord*/, const Eigen::MatrixBase & /*f*/, -Eigen::MatrixBase & /*normals*/) { } +inline void +ElementClass<_point_1, _ek_regular>::computeNormalsOnNaturalCoordinates( + const Eigen::MatrixBase & /*coord*/, + const Eigen::MatrixBase & /*f*/, Eigen::MatrixBase & /*normals*/) {} /* --------------r------------------------------------------------------------ */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_point_1>::computeShapes( const Eigen::MatrixBase & /*natural_coords*/, Eigen::MatrixBase & N) { N(0) = 1; /// N1(q_0) } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_point_1>::computeDNDS( const Eigen::MatrixBase & /*natural_coords*/, Eigen::MatrixBase & /*dnds*/) {} /* -------------------------------------------------------------------------- */ template <> template inline Real InterpolationElement<_itp_lagrange_point_1>::computeSpecialJacobian( const Eigen::MatrixBase & /*J*/) { return 0.; } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_point>::getInradius( +constexpr inline Real GeometricalElement<_gt_point>::getInradius( const Eigen::MatrixBase & /*coord*/) { return 0.; } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.hh b/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.hh index 802d9b43e..d8303fcc6 100644 --- a/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_quadrangle_4_inline_impl.hh @@ -1,170 +1,170 @@ /** * @file element_class_quadrangle_4_inline_impl.hh * * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Mon Dec 13 2010 * @date last modification: Fri Dec 11 2020 * * @brief Specialization of the element_class class for the type _quadrangle_4 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim \eta ^ (-1,1) | (1,1) x---------x | | | | | | --|---------|-----> \xi | | | | | | x---------x (-1,-1) | (1,-1) @endverbatim * * @f[ * \begin{array}{lll} * N1 = (1 - \xi) (1 - \eta) / 4 * & \frac{\partial N1}{\partial \xi} = - (1 - \eta) / 4 * & \frac{\partial N1}{\partial \eta} = - (1 - \xi) / 4 \\ * N2 = (1 + \xi) (1 - \eta) / 4 \\ * & \frac{\partial N2}{\partial \xi} = (1 - \eta) / 4 * & \frac{\partial N2}{\partial \eta} = - (1 + \xi) / 4 \\ * N3 = (1 + \xi) (1 + \eta) / 4 \\ * & \frac{\partial N3}{\partial \xi} = (1 + \eta) / 4 * & \frac{\partial N3}{\partial \eta} = (1 + \xi) / 4 \\ * N4 = (1 - \xi) (1 + \eta) / 4 * & \frac{\partial N4}{\partial \xi} = - (1 + \eta) / 4 * & \frac{\partial N4}{\partial \eta} = (1 - \xi) / 4 \\ * \end{array} * @f] * * @f{eqnarray*}{ * \xi_{q0} &=& 0 \qquad \eta_{q0} = 0 * @f} */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_quadrangle_4, _gt_quadrangle_4, _itp_lagrange_quadrangle_4, _ek_regular, 2, _git_segment, 2); /* -------------------------------------------------------------------------- */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_quadrangle_4>::computeShapes( const Eigen::MatrixBase & c, Eigen::MatrixBase & N) { N(0) = 1. / 4. * (1. - c(0)) * (1. - c(1)); /// N1(q_0) N(1) = 1. / 4. * (1. + c(0)) * (1. - c(1)); /// N2(q_0) N(2) = 1. / 4. * (1. + c(0)) * (1. + c(1)); /// N3(q_0) N(3) = 1. / 4. * (1. - c(0)) * (1. + c(1)); /// N4(q_0) } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_quadrangle_4>::computeDNDS( const Eigen::MatrixBase & c, Eigen::MatrixBase & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial * N4}{\partial \xi}\\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial * N4}{\partial \eta} * \end{array} * \right) * @f] */ dnds(0, 0) = -1. / 4. * (1. - c(1)); dnds(0, 1) = 1. / 4. * (1. - c(1)); dnds(0, 2) = 1. / 4. * (1. + c(1)); dnds(0, 3) = -1. / 4. * (1. + c(1)); dnds(1, 0) = -1. / 4. * (1. - c(0)); dnds(1, 1) = -1. / 4. * (1. + c(0)); dnds(1, 2) = 1. / 4. * (1. + c(0)); dnds(1, 3) = 1. / 4. * (1. - c(0)); } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_quadrangle_4>::computeD2NDS2( const vector_type & /*c*/, matrix_type & d2nds2) { d2nds2.zero(); d2nds2(1, 0) = 1. / 4.; d2nds2(1, 1) = -1. / 4.; d2nds2(1, 2) = 1. / 4.; d2nds2(1, 3) = -1. / 4.; d2nds2(2, 0) = 1. / 4.; d2nds2(2, 1) = -1. / 4.; d2nds2(2, 2) = 1. / 4.; d2nds2(2, 3) = -1. / 4.; } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_quadrangle_4>::getInradius( +constexpr inline Real GeometricalElement<_gt_quadrangle_4>::getInradius( const Eigen::MatrixBase & coord) { auto && u0 = coord.col(0); auto && u1 = coord.col(1); auto && u2 = coord.col(2); auto && u3 = coord.col(3); Real a = (u0 - u1).norm(); Real b = (u1 - u2).norm(); Real c = (u2 - u3).norm(); Real d = (u3 - u0).norm(); // Real septimetre = (a + b + c + d) / 2.; // Real p = Math::distance_2d(coord + 0, coord + 4); // Real q = Math::distance_2d(coord + 2, coord + 6); // Real area = sqrt(4*(p*p * q*q) - (a*a + b*b + c*c + d*d)*(a*a + c*c - b*b - // d*d)) / 4.; // Real h = sqrt(area); // to get a length // Real h = area / septimetre; // formula of inradius for circumscritable // quadrelateral Real h = std::min({a, b, c, d}); return h; } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_segment_2_inline_impl.hh b/src/fe_engine/element_classes/element_class_segment_2_inline_impl.hh index e62bf6482..f122b03a7 100644 --- a/src/fe_engine/element_classes/element_class_segment_2_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_segment_2_inline_impl.hh @@ -1,115 +1,115 @@ /** * @file element_class_segment_2_inline_impl.hh * * @author Emil Gallyamov * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Fri Jul 16 2010 * @date last modification: Fri Dec 11 2020 * * @brief Specialization of the element_class class for the type _segment_2 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim q --x--------|--------x---> x -1 0 1 @endverbatim * * @f{eqnarray*}{ * w_1(x) &=& 1/2(1 - x) \\ * w_2(x) &=& 1/2(1 + x) * @f} * * @f{eqnarray*}{ * x_{q} &=& 0 * @f} */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_segment_2, _gt_segment_2, _itp_lagrange_segment_2, _ek_regular, 1, _git_segment, 1); /* -------------------------------------------------------------------------- */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_segment_2>::computeShapes( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & N) { /// natural coordinate Real c = natural_coords(0); /// shape functions N(0) = 0.5 * (1 - c); N(1) = 0.5 * (1 + c); } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_segment_2>::computeDNDS( const Eigen::MatrixBase & /*natural_coords*/, Eigen::MatrixBase & dnds) { /// dN1/de dnds(0, 0) = -.5; /// dN2/de dnds(0, 1) = .5; } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_segment_2>::computeD2NDS2( const vector_type & /*natural_coords*/, matrix_type & d2nds2) { d2nds2.zero(); } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_segment_2>::getInradius( +constexpr inline Real GeometricalElement<_gt_segment_2>::getInradius( const Eigen::MatrixBase & coord) { return (coord.col(1) - coord.col(0)).norm(); } /* -------------------------------------------------------------------------- */ template <> template inline void GeometricalElement<_gt_segment_2>::getNormal( const Eigen::MatrixBase & coord, Eigen::MatrixBase & normal) { AKANTU_DEBUG_ASSERT(normal.size() == 2, "The normal is only uniquely defined in 2D"); Math::normal(coord.col(0) - coord.col(1), normal); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_segment_3_inline_impl.hh b/src/fe_engine/element_classes/element_class_segment_3_inline_impl.hh index 60d217f99..b0b672d00 100644 --- a/src/fe_engine/element_classes/element_class_segment_3_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_segment_3_inline_impl.hh @@ -1,117 +1,117 @@ /** * @file element_class_segment_3_inline_impl.hh * * @author Emil Gallyamov * @author Nicolas Richart * * @date creation: Fri Jul 16 2010 * @date last modification: Wed Dec 09 2020 * * @brief Specialization of the element_class class for the type _segment_3 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim -1 0 1 -----x---------x---------x-----> x 1 3 2 @endverbatim * * * @f[ * \begin{array}{lll} * x_{1} = -1 & x_{2} = 1 & x_{3} = 0 * \end{array} * @f] * * @f[ * \begin{array}{ll} * w_1(x) = \frac{x}{2}(x - 1) & w'_1(x) = x - \frac{1}{2}\\ * w_2(x) = \frac{x}{2}(x + 1) & w'_2(x) = x + \frac{1}{2}\\ * w_3(x) = 1-x^2 & w'_3(x) = -2x * \end{array} * @f] * * @f[ * \begin{array}{ll} * x_{q1} = -1/\sqrt{3} & x_{q2} = 1/\sqrt{3} * \end{array} * @f] */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_segment_3, _gt_segment_3, _itp_lagrange_segment_3, _ek_regular, 1, _git_segment, 2); /* -------------------------------------------------------------------------- */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_segment_3>::computeShapes( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & N) { Real c = natural_coords(0); N(0) = (c - 1) * c / 2; N(1) = (c + 1) * c / 2; N(2) = 1 - c * c; } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_segment_3>::computeDNDS( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & dnds) { Real c = natural_coords(0); dnds(0, 0) = c - .5; dnds(0, 1) = c + .5; dnds(0, 2) = -2 * c; } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_segment_3>::getInradius( +constexpr inline Real GeometricalElement<_gt_segment_3>::getInradius( const Eigen::MatrixBase & coord) { auto dist1 = (coord(1) - coord(0)).norm(); auto dist2 = (coord(2) - coord(1)).norm(); return std::min(dist1, dist2); } /* -------------------------------------------------------------------------- */ template <> template inline void GeometricalElement<_gt_segment_3>::getNormal( const Eigen::MatrixBase & coord, Eigen::MatrixBase & normal) { Eigen::Matrix natural_coords; natural_coords << .5; ElementClass<_segment_3>::computeNormalsOnNaturalCoordinates(natural_coords, coord, normal); } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.hh b/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.hh index 86bee5f3b..0ba54945c 100644 --- a/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.hh @@ -1,292 +1,288 @@ /** * @file element_class_tetrahedron_10_inline_impl.hh * * @author Guillaume Anciaux * @author Nicolas Richart * @author Peter Spijker * * @date creation: Fri Jul 16 2010 * @date last modification: Fri Feb 07 2020 * * @brief Specialization of the element_class class for the type * _tetrahedron_10 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim \zeta ^ | (0,0,1) x |` . | ` . | ` . | ` . (0,0.5,0.5) | ` x. | q4 o ` . \eta | ` . -, (0,0,0.5) x ` x (0.5,0,0.5) - | ` x-(0,1,0) | q3 o` - ' | (0,0.5,0) - ` ' | x- ` x (0.5,0.5,0) | q1 o - o q2` ' | - ` ' | - ` ' x---------------x--------------` x-----> \xi (0,0,0) (0.5,0,0) (1,0,0) @endverbatim * * * @f[ * \begin{array}{lll} * \xi_{0} = 0 & \eta_{0} = 0 & \zeta_{0} = 0 \\ * \xi_{1} = 1 & \eta_{1} = 0 & \zeta_{1} = 0 \\ * \xi_{2} = 0 & \eta_{2} = 1 & \zeta_{2} = 0 \\ * \xi_{3} = 0 & \eta_{3} = 0 & \zeta_{3} = 1 \\ * \xi_{4} = 1/2 & \eta_{4} = 0 & \zeta_{4} = 0 \\ * \xi_{5} = 1/2 & \eta_{5} = 1/2 & \zeta_{5} = 0 \\ * \xi_{6} = 0 & \eta_{6} = 1/2 & \zeta_{6} = 0 \\ * \xi_{7} = 0 & \eta_{7} = 0 & \zeta_{7} = 1/2 \\ * \xi_{8} = 1/2 & \eta_{8} = 0 & \zeta_{8} = 1/2 \\ * \xi_{9} = 0 & \eta_{9} = 1/2 & \zeta_{9} = 1/2 * \end{array} * @f] * * @f[ * \begin{array}{llll} * N1 = (1 - \xi - \eta - \zeta) (1 - 2 \xi - 2 \eta - 2 \zeta) * & \frac{\partial N1}{\partial \xi} = 4 \xi + 4 \eta + 4 \zeta - 3 * & \frac{\partial N1}{\partial \eta} = 4 \xi + 4 \eta + 4 \zeta - 3 * & \frac{\partial N1}{\partial \zeta} = 4 \xi + 4 \eta + 4 \zeta - 3 \\ * N2 = \xi (2 \xi - 1) * & \frac{\partial N2}{\partial \xi} = 4 \xi - 1 * & \frac{\partial N2}{\partial \eta} = 0 * & \frac{\partial N2}{\partial \zeta} = 0 \\ * N3 = \eta (2 \eta - 1) * & \frac{\partial N3}{\partial \xi} = 0 * & \frac{\partial N3}{\partial \eta} = 4 \eta - 1 * & \frac{\partial N3}{\partial \zeta} = 0 \\ * N4 = \zeta (2 \zeta - 1) * & \frac{\partial N4}{\partial \xi} = 0 * & \frac{\partial N4}{\partial \eta} = 0 * & \frac{\partial N4}{\partial \zeta} = 4 \zeta - 1 \\ * N5 = 4 \xi (1 - \xi - \eta - \zeta) * & \frac{\partial N5}{\partial \xi} = 4 - 8 \xi - 4 \eta - 4 \zeta * & \frac{\partial N5}{\partial \eta} = -4 \xi * & \frac{\partial N5}{\partial \zeta} = -4 \xi \\ * N6 = 4 \xi \eta * & \frac{\partial N6}{\partial \xi} = 4 \eta * & \frac{\partial N6}{\partial \eta} = 4 \xi * & \frac{\partial N6}{\partial \zeta} = 0 \\ * N7 = 4 \eta (1 - \xi - \eta - \zeta) * & \frac{\partial N7}{\partial \xi} = -4 \eta * & \frac{\partial N7}{\partial \eta} = 4 - 4 \xi - 8 \eta - 4 \zeta * & \frac{\partial N7}{\partial \zeta} = -4 \eta \\ * N8 = 4 \zeta (1 - \xi - \eta - \zeta) * & \frac{\partial N8}{\partial \xi} = -4 \zeta * & \frac{\partial N8}{\partial \eta} = -4 \zeta * & \frac{\partial N8}{\partial \zeta} = 4 - 4 \xi - 4 \eta - 8 \zeta \\ * N9 = 4 \zeta \xi * & \frac{\partial N9}{\partial \xi} = 4 \zeta * & \frac{\partial N9}{\partial \eta} = 0 * & \frac{\partial N9}{\partial \zeta} = 4 \xi \\ * N10 = 4 \eta \zeta * & \frac{\partial N10}{\partial \xi} = 0 * & \frac{\partial N10}{\partial \eta} = 4 \zeta * & \frac{\partial N10}{\partial \zeta} = 4 \eta \\ * \end{array} * @f] * * @f[ * a = \frac{5 - \sqrt{5}}{20}\\ * b = \frac{5 + 3 \sqrt{5}}{20} * \begin{array}{lll} * \xi_{q_0} = a & \eta_{q_0} = a & \zeta_{q_0} = a \\ * \xi_{q_1} = b & \eta_{q_1} = a & \zeta_{q_1} = a \\ * \xi_{q_2} = a & \eta_{q_2} = b & \zeta_{q_2} = a \\ * \xi_{q_3} = a & \eta_{q_3} = a & \zeta_{q_3} = b * \end{array} * @f] */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_tetrahedron_10, _gt_tetrahedron_10, _itp_lagrange_tetrahedron_10, _ek_regular, 3, _git_tetrahedron, 2); /* -------------------------------------------------------------------------- */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_tetrahedron_10>::computeShapes( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & N) { /// Natural coordinates Real xi = natural_coords(0); Real eta = natural_coords(1); Real zeta = natural_coords(2); Real sum = xi + eta + zeta; Real c0 = 1 - sum; Real c1 = 1 - 2 * sum; Real c2 = 2 * xi - 1; Real c3 = 2 * eta - 1; Real c4 = 2 * zeta - 1; /// Shape functions N(0) = c0 * c1; N(1) = xi * c2; N(2) = eta * c3; N(3) = zeta * c4; N(4) = 4 * xi * c0; N(5) = 4 * xi * eta; N(6) = 4 * eta * c0; N(7) = 4 * zeta * c0; N(8) = 4 * xi * zeta; N(9) = 4 * eta * zeta; } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_tetrahedron_10>::computeDNDS( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & dnds) { /** * \f[ * dnds = \left( * \begin{array}{cccccccccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial N4}{\partial * \xi} * & \frac{\partial N5}{\partial \xi} & \frac{\partial N6}{\partial * \xi} * & \frac{\partial N7}{\partial \xi} & \frac{\partial N8}{\partial * \xi} * & \frac{\partial N9}{\partial \xi} & \frac{\partial * N10}{\partial \xi} \\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial N4}{\partial * \eta} * & \frac{\partial N5}{\partial \eta} & \frac{\partial N6}{\partial * \eta} * & \frac{\partial N7}{\partial \eta} & \frac{\partial N8}{\partial * \eta} * & \frac{\partial N9}{\partial \eta} & \frac{\partial * N10}{\partial \eta} \\ * \frac{\partial N1}{\partial \zeta} & \frac{\partial N2}{\partial * \zeta} * & \frac{\partial N3}{\partial \zeta} & \frac{\partial N4}{\partial * \zeta} * & \frac{\partial N5}{\partial \zeta} & \frac{\partial N6}{\partial * \zeta} * & \frac{\partial N7}{\partial \zeta} & \frac{\partial N8}{\partial * \zeta} * & \frac{\partial N9}{\partial \zeta} & \frac{\partial * N10}{\partial \zeta} * \end{array} * \right) * \f] */ /// Natural coordinates Real xi = natural_coords(0); Real eta = natural_coords(1); Real zeta = natural_coords(2); Real sum = xi + eta + zeta; /// \frac{\partial N_i}{\partial \xi} dnds(0, 0) = 4 * sum - 3; dnds(0, 1) = 4 * xi - 1; dnds(0, 2) = 0; dnds(0, 3) = 0; dnds(0, 4) = 4 * (1 - sum - xi); dnds(0, 5) = 4 * eta; dnds(0, 6) = -4 * eta; dnds(0, 7) = -4 * zeta; dnds(0, 8) = 4 * zeta; dnds(0, 9) = 0; /// \frac{\partial N_i}{\partial \eta} dnds(1, 0) = 4 * sum - 3; dnds(1, 1) = 0; dnds(1, 2) = 4 * eta - 1; dnds(1, 3) = 0; dnds(1, 4) = -4 * xi; dnds(1, 5) = 4 * xi; dnds(1, 6) = 4 * (1 - sum - eta); dnds(1, 7) = -4 * zeta; dnds(1, 8) = 0; dnds(1, 9) = 4 * zeta; /// \frac{\partial N_i}{\partial \zeta} dnds(2, 0) = 4 * sum - 3; dnds(2, 1) = 0; dnds(2, 2) = 0; dnds(2, 3) = 4 * zeta - 1; dnds(2, 4) = -4 * xi; dnds(2, 5) = 0; dnds(2, 6) = -4 * eta; dnds(2, 7) = 4 * (1 - sum - zeta); dnds(2, 8) = 4 * xi; dnds(2, 9) = 4 * eta; } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_tetrahedron_10>::getInradius( +constexpr inline Real GeometricalElement<_gt_tetrahedron_10>::getInradius( const Eigen::MatrixBase & coord) { // Only take the four corner tetrahedra - Matrix tetrahedra; - // clang-format off - tetrahedra << 0, 4, 6, 7, - 4, 1, 5, 8, - 6, 5, 2, 9, - 7, 8, 9, 3; - // clang-format on + + Matrix tetrahedra{ + {0, 4, 6, 7}, {4, 1, 5, 8}, {6, 5, 2, 9}, {7, 8, 9, 3}}; auto inradius = std::numeric_limits::max(); for (Int t = 0; t < 4; t++) { auto ir = Math::tetrahedron_inradius( coord.col(tetrahedra(t, 0)), coord.col(tetrahedra(t, 1)), coord.col(tetrahedra(t, 2)), coord.col(tetrahedra(t, 3))); inradius = std::min(ir, inradius); } return 2. * inradius; } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.hh b/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.hh index e457f08e9..e2e6fa88f 100644 --- a/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.hh @@ -1,142 +1,144 @@ /** * @file element_class_tetrahedron_4_inline_impl.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Fri Jul 16 2010 * @date last modification: Wed Jun 17 2020 * * @brief Specialization of the element_class class for the type _tetrahedron_4 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim \eta ^ | x (0,0,1,0) |` | ` ° \zeta | ` ° - | ` x (0,0,0,1) | q.` - ' | -` ' | - ` ' | - ` ' x------------------x-----> \xi (1,0,0,0) (0,1,0,0) @endverbatim * * @f{eqnarray*}{ * N1 &=& 1 - \xi - \eta - \zeta \\ * N2 &=& \xi \\ * N3 &=& \eta \\ * N4 &=& \zeta * @f} * * @f[ * \xi_{q0} = 1/4 \qquad \eta_{q0} = 1/4 \qquad \zeta_{q0} = 1/4 * @f] */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_tetrahedron_4, _gt_tetrahedron_4, _itp_lagrange_tetrahedron_4, _ek_regular, 3, _git_tetrahedron, 1); /* -------------------------------------------------------------------------- */ template <> -template::value> *> +template ::value> *> inline void InterpolationElement<_itp_lagrange_tetrahedron_4>::computeShapes( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & N) { Real c0 = 1 - natural_coords(0) - natural_coords(1) - natural_coords(2); /// @f$ c0 = 1 - \xi - \eta - \zeta @f$ Real c1 = natural_coords(1); /// @f$ c1 = \xi @f$ Real c2 = natural_coords(2); /// @f$ c2 = \eta @f$ Real c3 = natural_coords(0); /// @f$ c3 = \zeta @f$ N(0) = c0; N(1) = c1; N(2) = c2; N(3) = c3; } /* -------------------------------------------------------------------------- */ template <> -template +template inline void InterpolationElement<_itp_lagrange_tetrahedron_4>::computeDNDS( - const Eigen::MatrixBase & /*natural_coords*/, Eigen::MatrixBase & dnds) { + const Eigen::MatrixBase & /*natural_coords*/, + Eigen::MatrixBase & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccc} * \frac{\partial N1}{\partial \xi} & \frac{\partial N2}{\partial * \xi} * & \frac{\partial N3}{\partial \xi} & \frac{\partial N4}{\partial * \xi} \\ * \frac{\partial N1}{\partial \eta} & \frac{\partial N2}{\partial * \eta} * & \frac{\partial N3}{\partial \eta} & \frac{\partial N4}{\partial * \eta} \\ * \frac{\partial N1}{\partial \zeta} & \frac{\partial N2}{\partial * \zeta} * & \frac{\partial N3}{\partial \zeta} & \frac{\partial N4}{\partial * \zeta} * \end{array} * \right) * @f] */ dnds(0, 0) = -1.; dnds(1, 0) = -1.; dnds(2, 0) = -1.; dnds(0, 1) = 0.; dnds(1, 1) = 1.; dnds(2, 1) = 0.; dnds(0, 2) = 0.; dnds(1, 2) = 0.; dnds(2, 2) = 1.; dnds(0, 3) = 1.; dnds(1, 3) = 0.; dnds(2, 3) = 0.; } /* -------------------------------------------------------------------------- */ template <> -template -inline Real -GeometricalElement<_gt_tetrahedron_4>::getInradius(const Eigen::MatrixBase & coord) { +template +constexpr inline Real GeometricalElement<_gt_tetrahedron_4>::getInradius( + const Eigen::MatrixBase & coord) { return 2. * Math::tetrahedron_inradius(coord.col(0), coord.col(1), coord.col(2), coord.col(3)); } } // namespace akantu diff --git a/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.hh b/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.hh index 98ea83941..31c9bac1d 100644 --- a/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.hh +++ b/src/fe_engine/element_classes/element_class_triangle_6_inline_impl.hh @@ -1,192 +1,192 @@ /** * @file element_class_triangle_6_inline_impl.hh * * @author Guillaume Anciaux * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Fri Jul 16 2010 * @date last modification: Fri Feb 28 2020 * * @brief Specialization of the element_class class for the type _triangle_6 * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /** * @verbatim \eta ^ | x 2 | ` | ` | . ` | q2 ` 5 x x 4 | ` | ` | .q0 q1. ` | ` x---------x---------x-----> \xi 0 3 1 @endverbatim * * * @f[ * \begin{array}{ll} * \xi_{0} = 0 & \eta_{0} = 0 \\ * \xi_{1} = 1 & \eta_{1} = 0 \\ * \xi_{2} = 0 & \eta_{2} = 1 \\ * \xi_{3} = 1/2 & \eta_{3} = 0 \\ * \xi_{4} = 1/2 & \eta_{4} = 1/2 \\ * \xi_{5} = 0 & \eta_{5} = 1/2 * \end{array} * @f] * * @f[ * \begin{array}{lll} * N1 = -(1 - \xi - \eta) (1 - 2 (1 - \xi - \eta)) * & \frac{\partial N1}{\partial \xi} = 1 - 4(1 - \xi - \eta) * & \frac{\partial N1}{\partial \eta} = 1 - 4(1 - \xi - \eta) \\ * N2 = - \xi (1 - 2 \xi) * & \frac{\partial N2}{\partial \xi} = - 1 + 4 \xi * & \frac{\partial N2}{\partial \eta} = 0 \\ * N3 = - \eta (1 - 2 \eta) * & \frac{\partial N3}{\partial \xi} = 0 * & \frac{\partial N3}{\partial \eta} = - 1 + 4 \eta \\ * N4 = 4 \xi (1 - \xi - \eta) * & \frac{\partial N4}{\partial \xi} = 4 (1 - 2 \xi - \eta) * & \frac{\partial N4}{\partial \eta} = - 4 \xi \\ * N5 = 4 \xi \eta * & \frac{\partial N5}{\partial \xi} = 4 \eta * & \frac{\partial N5}{\partial \eta} = 4 \xi \\ * N6 = 4 \eta (1 - \xi - \eta) * & \frac{\partial N6}{\partial \xi} = - 4 \eta * & \frac{\partial N6}{\partial \eta} = 4 (1 - \xi - 2 \eta) * \end{array} * @f] * * @f{eqnarray*}{ * \xi_{q0} &=& 1/6 \qquad \eta_{q0} = 1/6 \\ * \xi_{q1} &=& 2/3 \qquad \eta_{q1} = 1/6 \\ * \xi_{q2} &=& 1/6 \qquad \eta_{q2} = 2/3 * @f} */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_triangle_6, _gt_triangle_6, _itp_lagrange_triangle_6, _ek_regular, 2, _git_triangle, 2); /* -------------------------------------------------------------------------- */ template <> template ::value> *> inline void InterpolationElement<_itp_lagrange_triangle_6>::computeShapes( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & N) { /// Natural coordinates Real c0 = 1 - natural_coords(0) - natural_coords(1); /// @f$ c0 = 1 - \xi - \eta @f$ Real c1 = natural_coords(0); /// @f$ c1 = \xi @f$ Real c2 = natural_coords(1); /// @f$ c2 = \eta @f$ N(0) = c0 * (2 * c0 - 1.); N(1) = c1 * (2 * c1 - 1.); N(2) = c2 * (2 * c2 - 1.); N(3) = 4 * c0 * c1; N(4) = 4 * c1 * c2; N(5) = 4 * c2 * c0; } /* -------------------------------------------------------------------------- */ template <> template inline void InterpolationElement<_itp_lagrange_triangle_6>::computeDNDS( const Eigen::MatrixBase & natural_coords, Eigen::MatrixBase & dnds) { /** * @f[ * dnds = \left( * \begin{array}{cccccc} * \frac{\partial N1}{\partial \xi} * & \frac{\partial N2}{\partial \xi} * & \frac{\partial N3}{\partial \xi} * & \frac{\partial N4}{\partial \xi} * & \frac{\partial N5}{\partial \xi} * & \frac{\partial N6}{\partial \xi} \\ * * \frac{\partial N1}{\partial \eta} * & \frac{\partial N2}{\partial \eta} * & \frac{\partial N3}{\partial \eta} * & \frac{\partial N4}{\partial \eta} * & \frac{\partial N5}{\partial \eta} * & \frac{\partial N6}{\partial \eta} * \end{array} * \right) * @f] */ /// Natural coordinates Real c0 = 1 - natural_coords(0) - natural_coords(1); /// @f$ c0 = 1 - \xi - \eta @f$ Real c1 = natural_coords(0); /// @f$ c1 = \xi @f$ Real c2 = natural_coords(1); /// @f$ c2 = \eta @f$ dnds(0, 0) = 1 - 4 * c0; dnds(0, 1) = 4 * c1 - 1.; dnds(0, 2) = 0.; dnds(0, 3) = 4 * (c0 - c1); dnds(0, 4) = 4 * c2; dnds(0, 5) = -4 * c2; dnds(1, 0) = 1 - 4 * c0; dnds(1, 1) = 0.; dnds(1, 2) = 4 * c2 - 1.; dnds(1, 3) = -4 * c1; dnds(1, 4) = 4 * c1; dnds(1, 5) = 4 * (c0 - c2); } /* -------------------------------------------------------------------------- */ template <> template -inline Real GeometricalElement<_gt_triangle_6>::getInradius( +constexpr inline Real GeometricalElement<_gt_triangle_6>::getInradius( const Eigen::MatrixBase & coord) { UInt triangles[4][3] = {{0, 3, 5}, {3, 1, 4}, {3, 4, 5}, {5, 4, 2}}; Real inradius = std::numeric_limits::max(); for (Int t = 0; t < 4; t++) { auto ir = Math::triangle_inradius( coord(triangles[t][0]), coord(triangles[t][1]), coord(triangles[t][2])); inradius = std::min(ir, inradius); } return 2. * inradius; } } // namespace akantu diff --git a/src/fe_engine/integrator_gauss_inline_impl.hh b/src/fe_engine/integrator_gauss_inline_impl.hh index 2ab47479d..31ea7534c 100644 --- a/src/fe_engine/integrator_gauss_inline_impl.hh +++ b/src/fe_engine/integrator_gauss_inline_impl.hh @@ -1,633 +1,637 @@ /** * @file integrator_gauss_inline_impl.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Tue Feb 15 2011 * @date last modification: Tue Oct 27 2020 * * @brief inline function of gauss integrator * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "mesh_iterators.hh" /* -------------------------------------------------------------------------- */ namespace akantu { namespace debug { -struct IntegratorGaussException : public Exception {}; + struct IntegratorGaussException : public Exception {}; } // namespace debug /* -------------------------------------------------------------------------- */ template template inline void IntegratorGauss::integrateOnElement( - const Array &f, Real *intf, Int nb_degree_of_freedom, const Idx elem, - GhostType ghost_type) const { - auto &jac_loc = jacobians(type, ghost_type); + const Array & f, Real * intf, Int nb_degree_of_freedom, + const Idx elem, GhostType ghost_type) const { + auto & jac_loc = jacobians(type, ghost_type); auto nb_quadrature_points = ElementClass::getNbQuadraturePoints(); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom, "The vector f do not have the good number of component."); - auto *f_val = f.data() + elem * f.getNbComponent(); - auto *jac_val = jac_loc.data() + elem * nb_quadrature_points; + auto * f_val = f.data() + elem * f.getNbComponent(); + auto * jac_val = jac_loc.data() + elem * nb_quadrature_points; integrate(f_val, jac_val, intf, nb_degree_of_freedom, nb_quadrature_points); } /* -------------------------------------------------------------------------- */ template template inline Real IntegratorGauss::integrate( - const Vector &in_f, Idx index, GhostType ghost_type) const { - const Array &jac_loc = jacobians(type, ghost_type); + const Vector & in_f, Idx index, GhostType ghost_type) const { + const Array & jac_loc = jacobians(type, ghost_type); auto nb_quadrature_points = GaussIntegrationElement::getNbQuadraturePoints(); AKANTU_DEBUG_ASSERT(in_f.size() == nb_quadrature_points, "The vector f do not have nb_quadrature_points entries."); - auto *jac_val = jac_loc.data() + index * nb_quadrature_points; + auto * jac_val = jac_loc.data() + index * nb_quadrature_points; Real intf; integrate(in_f.data(), jac_val, &intf, 1, nb_quadrature_points); return intf; } /* -------------------------------------------------------------------------- */ template inline void IntegratorGauss::integrate( - const Real *f, const Real *jac, Real *inte, Int nb_degree_of_freedom, + const Real * f, const Real * jac, Real * inte, Int nb_degree_of_freedom, Int nb_quadrature_points) const { Eigen::Map inte_v(inte, nb_quadrature_points); Eigen::Map cjac(jac, nb_quadrature_points); Eigen::Map fq(f, nb_degree_of_freedom, nb_quadrature_points); inte_v.zero(); inte_v = fq * cjac; } /* -------------------------------------------------------------------------- */ template template inline const Matrix & IntegratorGauss::getIntegrationPoints( GhostType ghost_type) const { AKANTU_DEBUG_ASSERT( quadrature_points.exists(type, ghost_type), "Quadrature points for type " << quadrature_points.printType(type, ghost_type) << " have not been initialized." << " Did you use 'computeQuadraturePoints' function ?"); return (quadrature_points(type, ghost_type)); } /* -------------------------------------------------------------------------- */ template template inline Int IntegratorGauss::getNbIntegrationPoints( GhostType ghost_type) const { AKANTU_DEBUG_ASSERT( quadrature_points.exists(type, ghost_type), "Quadrature points for type " << quadrature_points.printType(type, ghost_type) << " have not been initialized." << " Did you use 'computeQuadraturePoints' function ?"); return quadrature_points(type, ghost_type).cols(); } /* -------------------------------------------------------------------------- */ template template inline Matrix IntegratorGauss::getIntegrationPoints() const { return GaussIntegrationElement::getQuadraturePoints(); } /* -------------------------------------------------------------------------- */ template template inline Vector IntegratorGauss::getIntegrationWeights() const { return GaussIntegrationElement::getWeights(); } /* -------------------------------------------------------------------------- */ template template inline void IntegratorGauss::computeQuadraturePoints( GhostType ghost_type) { - auto &quads = quadrature_points(type, ghost_type); + auto & quads = quadrature_points(type, ghost_type); constexpr auto polynomial_degree = IntegrationOrderFunctor::template getOrder(); quads = GaussIntegrationElement::getQuadraturePoints(); } /* -------------------------------------------------------------------------- */ template template inline void IntegratorGauss:: computeJacobianOnQuadPointsByElement( - const Eigen::MatrixBase &node_coords, - const Eigen::MatrixBase &quad, - Eigen::MatrixBase &jacobians) const { + const Eigen::MatrixBase & node_coords, + const Eigen::MatrixBase & quad, + Eigen::MatrixBase & jacobians) const { // jacobian ElementClass::computeJacobian(quad, node_coords, jacobians); } /* -------------------------------------------------------------------------- */ template IntegratorGauss::IntegratorGauss( - const Mesh &mesh, Int spatial_dimension, const ID &id) + const Mesh & mesh, Int spatial_dimension, const ID & id) : Integrator(mesh, spatial_dimension, id) {} /* -------------------------------------------------------------------------- */ template template void IntegratorGauss::checkJacobians( GhostType ghost_type) const { auto nb_quadrature_points = this->quadrature_points(type, ghost_type).cols(); auto nb_element = mesh.getConnectivity(type, ghost_type).size(); - auto *jacobians_val = jacobians(type, ghost_type).data(); + auto * jacobians_val = jacobians(type, ghost_type).data(); for (Idx i = 0; i < nb_element * nb_quadrature_points; ++i, ++jacobians_val) { if (*jacobians_val < 0) { AKANTU_CUSTOM_EXCEPTION_INFO(debug::IntegratorGaussException{}, "Negative jacobian computed," << " possible problem in the element " "node ordering (Quadrature Point " << i % nb_quadrature_points << ":" << i / nb_quadrature_points << ":" << type << ":" << ghost_type << ")"); } } } /* -------------------------------------------------------------------------- */ template template void IntegratorGauss:: computeJacobiansOnIntegrationPoints( - const Array &nodes, const Matrix &quad_points, - Array &jacobians, GhostType ghost_type, - const Array &filter_elements) const { + const Array & nodes, const Matrix & quad_points, + Array & jacobians, GhostType ghost_type, + const Array & filter_elements) const { auto spatial_dimension = mesh.getSpatialDimension(); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = quad_points.cols(); auto nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = make_view(jacobians, nb_quadrature_points).begin(); auto jacobians_begin = jacobians_it; Array x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = make_view(x_el, spatial_dimension, nb_nodes_per_element).begin(); nb_element = x_el.size(); // Matrix local_coord(spatial_dimension, nb_nodes_per_element); for (Idx elem = 0; elem < nb_element; ++elem, ++x_it) { - const auto &x = *x_it; + const auto & x = *x_it; if (filter_elements != empty_filter) { jacobians_it = jacobians_begin + filter_elements(elem); } computeJacobianOnQuadPointsByElement(x, quad_points, *jacobians_it); if (filter_elements == empty_filter) { ++jacobians_it; } } } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_STRUCTURAL_MECHANICS) template <> template void IntegratorGauss<_ek_structural, DefaultIntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( - const Array &nodes, const Matrix &quad_points, - Array &jacobians, GhostType ghost_type, - const Array &filter_elements) const { + const Array & nodes, const Matrix & quad_points, + Array & jacobians, GhostType ghost_type, + const Array & filter_elements) const { const auto spatial_dimension = mesh.getSpatialDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto nb_quadrature_points = quad_points.cols(); const auto nb_dofs = ElementClass::getNbDegreeOfFreedom(); auto nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_it = make_view(jacobians, nb_quadrature_points).begin(); auto jacobians_begin = jacobians_it; Array x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = make_view(x_el, spatial_dimension, nb_nodes_per_element).begin(); nb_element = x_el.size(); const auto has_extra_normal = mesh.hasData("extra_normal", type, ghost_type); Array::const_vector_iterator extra_normal; Array::const_vector_iterator extra_normal_begin; if (has_extra_normal) { extra_normal = mesh.getData("extra_normal", type, ghost_type) .begin(spatial_dimension); extra_normal_begin = extra_normal; } // Matrix local_coord(spatial_dimension, nb_nodes_per_element); for (Idx elem = 0; elem < nb_element; ++elem, ++x_it) { if (filter_elements != empty_filter) { jacobians_it = jacobians_begin + filter_elements(elem); - extra_normal = extra_normal_begin + filter_elements(elem); + if (has_extra_normal) { + extra_normal = extra_normal_begin + filter_elements(elem); + } } - const auto &X = *x_it; - auto &J = *jacobians_it; + const auto & X = *x_it; + auto & J = *jacobians_it; Matrix R(nb_dofs, nb_dofs); if (has_extra_normal) { ElementClass::computeRotationMatrix(R, X, *extra_normal); } else { ElementClass::computeRotationMatrix(R, X, Vector(X.rows())); } const Int natural_space = ElementClass::getNaturalSpaceDimension(); const Int nb_nodes = ElementClass::getNbNodesPerElement(); // Extracting relevant lines auto x = (R.block(0, 0, spatial_dimension, spatial_dimension) * X) .template block(0, 0); computeJacobianOnQuadPointsByElement(x, quad_points, J); if (filter_elements == empty_filter) { ++jacobians_it; - ++extra_normal; + if (has_extra_normal) { + ++extra_normal; + } } } } #endif /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) template <> template void IntegratorGauss<_ek_cohesive, DefaultIntegrationOrderFunctor>:: computeJacobiansOnIntegrationPoints( - const Array &nodes, const Matrix &quad_points, - Array &jacobians, GhostType ghost_type, - const Array &filter_elements) const { + const Array & nodes, const Matrix & quad_points, + Array & jacobians, GhostType ghost_type, + const Array & filter_elements) const { auto spatial_dimension = mesh.getSpatialDimension(); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = quad_points.cols(); auto nb_element = mesh.getNbElement(type, ghost_type); jacobians.resize(nb_element * nb_quadrature_points); auto jacobians_begin = make_view(jacobians, nb_quadrature_points).begin(); Array x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type, filter_elements); auto x_it = make_view(x_el, spatial_dimension, nb_nodes_per_element).begin(); auto nb_nodes_per_subelement = nb_nodes_per_element / 2; Matrix x(spatial_dimension, nb_nodes_per_subelement); nb_element = x_el.size(); Idx l_el = 0; - auto compute = [&](const auto &el) { - auto &&J = jacobians_begin[el]; - auto &&X = x_it[l_el]; + auto compute = [&](const auto & el) { + auto && J = jacobians_begin[el]; + auto && X = x_it[l_el]; ++l_el; for (Int n = 0; n < nb_nodes_per_subelement; ++n) x(n) = (X(n) + X(n + nb_nodes_per_subelement)) / 2.; if (type == _cohesive_1d_2) { J(0) = 1; } else { this->computeJacobianOnQuadPointsByElement(x, quad_points, J); } }; for_each_element(nb_element, filter_elements, compute); } #endif /* -------------------------------------------------------------------------- */ template template void IntegratorGauss:: - precomputeJacobiansOnQuadraturePoints(const Array &nodes, + precomputeJacobiansOnQuadraturePoints(const Array & nodes, GhostType ghost_type) { - auto &jacobians_tmp = jacobians.alloc(0, 1, type, ghost_type); + auto & jacobians_tmp = jacobians.alloc(0, 1, type, ghost_type); this->computeJacobiansOnIntegrationPoints( nodes, quadrature_points(type, ghost_type), jacobians_tmp, ghost_type); } /* -------------------------------------------------------------------------- */ template template void IntegratorGauss::multiplyJacobiansByWeights( - Array &jacobians, const Array &filter_elements) const { + Array & jacobians, const Array & filter_elements) const { constexpr auto nb_quadrature_points = GaussIntegrationElement::getNbQuadraturePoints(); - auto &&weights = + auto && weights = GaussIntegrationElement::getWeights(); - auto &&view = make_view(jacobians); + auto && view = make_view(jacobians); if (filter_elements != empty_filter) { - for (auto &&J : filter(filter_elements, view)) + for (auto && J : filter(filter_elements, view)) J.array() *= weights.array(); } else { - for (auto &&J : view) + for (auto && J : view) J.array() *= weights.array(); } } /* -------------------------------------------------------------------------- */ template void IntegratorGauss::integrate( - const Array &in_f, Array &intf, Int nb_degree_of_freedom, - const Array &jacobians, Int nb_element) const { + const Array & in_f, Array & intf, Int nb_degree_of_freedom, + const Array & jacobians, Int nb_element) const { intf.resize(nb_element); if (nb_element == 0) { return; } auto nb_points = jacobians.size() / nb_element; - for (auto &&data : zip(make_view(in_f, nb_degree_of_freedom, nb_points), - make_view(intf, nb_degree_of_freedom), - make_view(jacobians, nb_points))) { - auto &&f = std::get<0>(data); - auto &&int_f = std::get<1>(data); - auto &&J = std::get<2>(data); + for (auto && data : zip(make_view(in_f, nb_degree_of_freedom, nb_points), + make_view(intf, nb_degree_of_freedom), + make_view(jacobians, nb_points))) { + auto && f = std::get<0>(data); + auto && int_f = std::get<1>(data); + auto && J = std::get<2>(data); int_f = f * J; } } /* -------------------------------------------------------------------------- */ template template void IntegratorGauss::integrate( - const Array &in_f, Array &intf, Int nb_degree_of_freedom, - GhostType ghost_type, const Array &filter_elements) const { + const Array & in_f, Array & intf, Int nb_degree_of_freedom, + GhostType ghost_type, const Array & filter_elements) const { AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); - const auto &jac_loc = jacobians(type, ghost_type); + const auto & jac_loc = jacobians(type, ghost_type); if (filter_elements != empty_filter) { auto nb_element = filter_elements.size(); auto filtered_J = std::make_shared>(0, jac_loc.getNbComponent()); FEEngine::filterElementalData(mesh, jac_loc, *filtered_J, type, ghost_type, filter_elements); this->integrate(in_f, intf, nb_degree_of_freedom, *filtered_J, nb_element); } else { auto nb_element = mesh.getNbElement(type, ghost_type); this->integrate(in_f, intf, nb_degree_of_freedom, jac_loc, nb_element); } } /* -------------------------------------------------------------------------- */ template template void IntegratorGauss::integrate( - const Array &in_f, Array &intf, Int nb_degree_of_freedom, + const Array & in_f, Array & intf, Int nb_degree_of_freedom, GhostType ghost_type) const { auto quads = this->getIntegrationPoints(); Array jacobians; this->computeJacobiansOnIntegrationPoints(mesh.getNodes(), quads, jacobians, ghost_type); this->multiplyJacobiansByWeights(jacobians); this->integrate(in_f, intf, nb_degree_of_freedom, jacobians, mesh.getNbElement(type, ghost_type)); } /* -------------------------------------------------------------------------- */ template template Real IntegratorGauss::integrate( - const Array &in_f, GhostType ghost_type) const { + const Array & in_f, GhostType ghost_type) const { Array intfv(0, 1); integrate(in_f, intfv, 1, ghost_type); auto res = Math::reduce(intfv); return res; } /* -------------------------------------------------------------------------- */ template template Real IntegratorGauss::integrate( - const Array &in_f, GhostType ghost_type, - const Array &filter_elements) const { + const Array & in_f, GhostType ghost_type, + const Array & filter_elements) const { AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); Array intfv(0, 1); integrate(in_f, intfv, 1, ghost_type, filter_elements); auto res = Math::reduce(intfv); return res; } /* -------------------------------------------------------------------------- */ template void IntegratorGauss:: - integrateOnIntegrationPoints(const Array &in_f, Array &intf, + integrateOnIntegrationPoints(const Array & in_f, Array & intf, Int nb_degree_of_freedom, - const Array &jacobians, + const Array & jacobians, Int nb_element) const { auto nb_points = jacobians.size() / nb_element; intf.resize(nb_element * nb_points); auto J_it = jacobians.begin(); auto f_it = in_f.begin(nb_degree_of_freedom); auto inte_it = intf.begin(nb_degree_of_freedom); for (Idx el = 0; el < nb_element; ++el, ++J_it, ++f_it, ++inte_it) { - const auto &J = *J_it; - const auto &f = *f_it; - auto &inte_f = *inte_it; + const auto & J = *J_it; + const auto & f = *f_it; + auto & inte_f = *inte_it; inte_f = f; inte_f *= J; } } /* -------------------------------------------------------------------------- */ template template void IntegratorGauss:: - integrateOnIntegrationPoints(const Array &in_f, Array &intf, + integrateOnIntegrationPoints(const Array & in_f, Array & intf, Int nb_degree_of_freedom, GhostType ghost_type, - const Array &filter_elements) const { + const Array & filter_elements) const { AKANTU_DEBUG_ASSERT(jacobians.exists(type, ghost_type), "No jacobians for the type " << jacobians.printType(type, ghost_type)); - const auto &jac_loc = this->jacobians(type, ghost_type); + const auto & jac_loc = this->jacobians(type, ghost_type); if (filter_elements != empty_filter) { auto nb_element = filter_elements.size(); auto filtered_J = std::make_shared>(0, jac_loc.getNbComponent()); FEEngine::filterElementalData(mesh, jac_loc, *filtered_J, type, ghost_type, filter_elements); this->integrateOnIntegrationPoints(in_f, intf, nb_degree_of_freedom, *filtered_J, nb_element); } else { auto nb_element = mesh.getNbElement(type, ghost_type); this->integrateOnIntegrationPoints(in_f, intf, nb_degree_of_freedom, jac_loc, nb_element); } } /* -------------------------------------------------------------------------- */ template template inline void IntegratorGauss::onElementsAddedByType( - const Array &elements, GhostType ghost_type) { - const auto &nodes = mesh.getNodes(); + const Array & elements, GhostType ghost_type) { + const auto & nodes = mesh.getNodes(); if (not quadrature_points.exists(type, ghost_type)) { computeQuadraturePoints(ghost_type); } if (not jacobians.exists(type, ghost_type)) { jacobians.alloc(0, 1, type, ghost_type); } this->computeJacobiansOnIntegrationPoints( nodes, quadrature_points(type, ghost_type), jacobians(type, ghost_type), type, ghost_type, elements); constexpr auto polynomial_degree = IntegrationOrderFunctor::template getOrder(); this->multiplyJacobiansByWeights( this->jacobians(type, ghost_type), elements); } /* -------------------------------------------------------------------------- */ template void IntegratorGauss::onElementsAdded( - const Array &new_elements) { + const Array & new_elements) { for (auto elements_range : MeshElementsByTypes(new_elements)) { auto type = elements_range.getType(); auto ghost_type = elements_range.getGhostType(); if (mesh.getSpatialDimension(type) != _spatial_dimension) { continue; } if (mesh.getKind(type) != kind) { continue; } tuple_dispatch>( - [&](auto &&enum_type) { + [&](auto && enum_type) { constexpr auto type = std::decay_t::value; this->template onElementsAddedByType( elements_range.getElements(), ghost_type); }, type); } } /* -------------------------------------------------------------------------- */ template template inline void IntegratorGauss::initIntegrator( - const Array &nodes, GhostType ghost_type) { + const Array & nodes, GhostType ghost_type) { computeQuadraturePoints(ghost_type); precomputeJacobiansOnQuadraturePoints(nodes, ghost_type); checkJacobians(ghost_type); constexpr auto polynomial_degree = IntegrationOrderFunctor::template getOrder(); multiplyJacobiansByWeights( this->jacobians(type, ghost_type)); } /* -------------------------------------------------------------------------- */ template inline void IntegratorGauss::initIntegrator( - const Array &nodes, ElementType type, GhostType ghost_type) { + const Array & nodes, ElementType type, GhostType ghost_type) { tuple_dispatch>( - [&](auto &&enum_type) { + [&](auto && enum_type) { constexpr auto type = std::decay_t::value; this->template initIntegrator(nodes, ghost_type); }, type); } /* -------------------------------------------------------------------------- */ template void IntegratorGauss:: computeJacobiansOnIntegrationPoints( - const Array &nodes, const Matrix &quad_points, - Array &jacobians, ElementType type, GhostType ghost_type, - const Array &filter_elements) const { + const Array & nodes, const Matrix & quad_points, + Array & jacobians, ElementType type, GhostType ghost_type, + const Array & filter_elements) const { tuple_dispatch>( - [&](auto &&enum_type) { + [&](auto && enum_type) { constexpr auto type = std::decay_t::value; this->template computeJacobiansOnIntegrationPoints( nodes, quad_points, jacobians, ghost_type, filter_elements); }, type); } } // namespace akantu diff --git a/src/fe_engine/shape_structural_inline_impl.hh b/src/fe_engine/shape_structural_inline_impl.hh index 521a81849..f3cc83b6a 100644 --- a/src/fe_engine/shape_structural_inline_impl.hh +++ b/src/fe_engine/shape_structural_inline_impl.hh @@ -1,516 +1,516 @@ /** * @file shape_structural_inline_impl.hh * * @author Fabian Barras * @author Lucas Frerot * @author Nicolas Richart * * @date creation: Wed Oct 11 2017 * @date last modification: Mon Feb 01 2021 * * @brief ShapeStructural inline implementation * * * @section LICENSE * * Copyright (©) 2016-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_iterators.hh" #include "shape_structural.hh" /* -------------------------------------------------------------------------- */ //#ifndef AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_HH_ //#define AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_HH_ namespace akantu { namespace { - /// Extract nodal coordinates per elements - template - std::unique_ptr> getNodesPerElement(const Mesh & mesh, - const Array & nodes, - GhostType ghost_type) { - const auto dim = ElementClass::getSpatialDimension(); - const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); - - auto nodes_per_element = - std::make_unique>(0, dim * nb_nodes_per_element); - FEEngine::extractNodalToElementField(mesh, nodes, *nodes_per_element, type, - ghost_type); - return nodes_per_element; - } +/// Extract nodal coordinates per elements +template +std::unique_ptr> getNodesPerElement(const Mesh &mesh, + const Array &nodes, + GhostType ghost_type) { + const auto dim = ElementClass::getSpatialDimension(); + const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + + auto nodes_per_element = + std::make_unique>(0, dim * nb_nodes_per_element); + FEEngine::extractNodalToElementField(mesh, nodes, *nodes_per_element, type, + ghost_type); + return nodes_per_element; +} } // namespace template inline void ShapeStructural::initShapeFunctions( const Array & /* unused */, const Matrix & /* unused */, ElementType /* unused */, GhostType /* unused */) { AKANTU_TO_IMPLEMENT(); } template <> inline void ShapeStructural<_ek_structural>::initShapeFunctions( - const Array & nodes, const Matrix & integration_points, + const Array &nodes, const Matrix &integration_points, ElementType type, GhostType ghost_type) { tuple_dispatch>( - [&](auto && enum_type) { + [&](auto &&enum_type) { constexpr ElementType type = std::decay_t::value; this->setIntegrationPointsByType(integration_points, ghost_type); this->precomputeRotationMatrices(nodes, ghost_type); this->precomputeShapesOnIntegrationPoints(nodes, ghost_type); this->precomputeShapeDerivativesOnIntegrationPoints(nodes, ghost_type); }, type); } /* -------------------------------------------------------------------------- */ template template void ShapeStructural::computeShapesOnIntegrationPointsInternal( - const Array & nodes, const Matrix & integration_points, - Array & shapes, GhostType ghost_type, - const Array & filter_elements, bool mass) const { + const Array &nodes, const Matrix &integration_points, + Array &shapes, GhostType ghost_type, + const Array &filter_elements, bool mass) const { auto nb_points = integration_points.cols(); auto nb_element = mesh.getConnectivity(type, ghost_type).size(); auto nb_nodes_per_element = ElementClass::getNbNodesPerElement(); shapes.resize(nb_element * nb_points); auto nb_dofs = ElementClass::getNbDegreeOfFreedom(); auto nb_rows = nb_dofs; if (mass) { nb_rows = ElementClass::getNbStressComponents(); } #if !defined(AKANTU_NDEBUG) - UInt size_of_shapes = nb_rows * nb_dofs * nb_nodes_per_element; + Int size_of_shapes = nb_rows * nb_dofs * nb_nodes_per_element; AKANTU_DEBUG_ASSERT(shapes.getNbComponent() == size_of_shapes, "The shapes array does not have the correct " << "number of component"); #endif auto shapes_it = make_view(shapes, nb_rows, ElementClass::getNbNodesPerInterpolationElement() * nb_dofs, nb_points) .begin(); auto shapes_begin = shapes_it; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } auto nodes_per_element = getNodesPerElement(mesh, nodes, ghost_type); auto nodes_it = nodes_per_element->begin(mesh.getSpatialDimension(), Mesh::getNbNodesPerElement(type)); auto nodes_begin = nodes_it; auto rot_matrix_it = make_view(rotation_matrices(type, ghost_type), nb_dofs, nb_dofs).begin(); auto rot_matrix_begin = rot_matrix_it; for (Int elem = 0; elem < nb_element; ++elem) { if (filter_elements != empty_filter) { shapes_it = shapes_begin + filter_elements(elem); nodes_it = nodes_begin + filter_elements(elem); rot_matrix_it = rot_matrix_begin + filter_elements(elem); } Tensor3 N = *shapes_it; - auto & real_coord = *nodes_it; + auto &real_coord = *nodes_it; - auto & RDOFs = *rot_matrix_it; + auto &RDOFs = *rot_matrix_it; Matrix T(N.size(1), N.size(1)); T.zero(); for (Int i = 0; i < nb_nodes_per_element; ++i) { T.block(i * RDOFs.rows(), i * RDOFs.cols(), RDOFs.rows(), RDOFs.cols()) = RDOFs; } if (not mass) { ElementClass::computeShapes(integration_points, real_coord, T, N); } else { ElementClass::computeShapesMass(integration_points, real_coord, T, N); } if (filter_elements == empty_filter) { ++shapes_it; ++nodes_it; } } } /* -------------------------------------------------------------------------- */ template template -void ShapeStructural::precomputeRotationMatrices( - const Array & nodes, GhostType ghost_type) { +void ShapeStructural::precomputeRotationMatrices(const Array &nodes, + GhostType ghost_type) { AKANTU_DEBUG_IN(); const auto spatial_dimension = mesh.getSpatialDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto nb_element = mesh.getNbElement(type, ghost_type); const auto nb_dof = ElementClass::getNbDegreeOfFreedom(); if (not this->rotation_matrices.exists(type, ghost_type)) { this->rotation_matrices.alloc(0, nb_dof * nb_dof, type, ghost_type); } - auto & rot_matrices = this->rotation_matrices(type, ghost_type); + auto &rot_matrices = this->rotation_matrices(type, ghost_type); rot_matrices.resize(nb_element); Array x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type); bool has_extra_normal = mesh.hasData("extra_normal", type, ghost_type); Array::const_vector_iterator extra_normal; if (has_extra_normal) { extra_normal = mesh.getData("extra_normal", type, ghost_type) .begin(spatial_dimension); } - for (auto && tuple : + for (auto &&tuple : zip(make_view(x_el, spatial_dimension, nb_nodes_per_element), make_view(rot_matrices, nb_dof, nb_dof))) { // compute shape derivatives - auto & X = std::get<0>(tuple); - auto & R = std::get<1>(tuple); + auto &X = std::get<0>(tuple); + auto &R = std::get<1>(tuple); if (has_extra_normal) { ElementClass::computeRotationMatrix(R, X, *extra_normal); ++extra_normal; } else { ElementClass::computeRotationMatrix( R, X, Vector(spatial_dimension)); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template template void ShapeStructural::precomputeShapesOnIntegrationPoints( - const Array & nodes, GhostType ghost_type) { + const Array &nodes, GhostType ghost_type) { AKANTU_DEBUG_IN(); - const auto & natural_coords = integration_points(type, ghost_type); + const auto &natural_coords = integration_points(type, ghost_type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_points = integration_points(type, ghost_type).cols(); auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_dof = ElementClass::getNbDegreeOfFreedom(); const auto dim = ElementClass::getSpatialDimension(); const auto spatial_dimension = mesh.getSpatialDimension(); const auto natural_spatial_dimension = ElementClass::getNaturalSpaceDimension(); auto itp_type = FEEngine::getInterpolationType(type); if (not shapes.exists(itp_type, ghost_type)) { auto size_of_shapes = this->getShapeSize(type); this->shapes.alloc(0, size_of_shapes, itp_type, ghost_type); } - auto & rot_matrices = this->rotation_matrices(type, ghost_type); - auto & shapes_ = this->shapes(itp_type, ghost_type); + auto &rot_matrices = this->rotation_matrices(type, ghost_type); + auto &shapes_ = this->shapes(itp_type, ghost_type); shapes_.resize(nb_element * nb_points); auto nodes_per_element = getNodesPerElement(mesh, nodes, ghost_type); - for (auto && tuple : + for (auto &&tuple : zip(make_view(shapes_, nb_dof, nb_dof * nb_nodes_per_element, nb_points), make_view(*nodes_per_element, dim, nb_nodes_per_element), make_view(rot_matrices, nb_dof, nb_dof))) { - auto && N = std::get<0>(tuple); - auto && X = std::get<1>(tuple); - auto && RDOFs = std::get<2>(tuple); + auto &&N = std::get<0>(tuple); + auto &&X = std::get<1>(tuple); + auto &&RDOFs = std::get<2>(tuple); Matrix T(N.size(1), N.size(1)); T.zero(); for (Idx i = 0; i < nb_nodes_per_element; ++i) { T.block(i * RDOFs.rows(), i * RDOFs.cols(), RDOFs.rows(), RDOFs.cols()) = RDOFs; } auto R = RDOFs.block(0, 0, spatial_dimension, spatial_dimension); // Rotate to local basis auto x = (R * X).block(0, 0, natural_spatial_dimension, nb_nodes_per_element); ElementClass::computeShapes(natural_coords, x, T, N); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template template void ShapeStructural::precomputeShapeDerivativesOnIntegrationPoints( - const Array & nodes, GhostType ghost_type) { + const Array &nodes, GhostType ghost_type) { AKANTU_DEBUG_IN(); - const auto & natural_coords = integration_points(type, ghost_type); + const auto &natural_coords = integration_points(type, ghost_type); const auto spatial_dimension = mesh.getSpatialDimension(); const auto natural_spatial_dimension = ElementClass::getNaturalSpaceDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto nb_points = natural_coords.cols(); const auto nb_dof = ElementClass::getNbDegreeOfFreedom(); const auto nb_element = mesh.getNbElement(type, ghost_type); const auto nb_stress_components = ElementClass::getNbStressComponents(); auto itp_type = FEEngine::getInterpolationType(type); if (not this->shapes_derivatives.exists(itp_type, ghost_type)) { auto size_of_shapesd = this->getShapeDerivativesSize(type); this->shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); } - auto & rot_matrices = this->rotation_matrices(type, ghost_type); + auto &rot_matrices = this->rotation_matrices(type, ghost_type); Array x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type); - auto & shapesd = this->shapes_derivatives(itp_type, ghost_type); + auto &shapesd = this->shapes_derivatives(itp_type, ghost_type); shapesd.resize(nb_element * nb_points); - for (auto && tuple : + for (auto &&tuple : zip(make_view(x_el, spatial_dimension, nb_nodes_per_element), make_view(shapesd, nb_stress_components, nb_nodes_per_element * nb_dof, nb_points), make_view(rot_matrices, nb_dof, nb_dof))) { // compute shape derivatives - auto & X = std::get<0>(tuple); - auto & B = std::get<1>(tuple); - auto & RDOFs = std::get<2>(tuple); + auto &X = std::get<0>(tuple); + auto &B = std::get<1>(tuple); + auto &RDOFs = std::get<2>(tuple); Tensor3 dnds(natural_spatial_dimension, ElementClass::interpolation_property::dnds_columns, B.size(2)); ElementClass::computeDNDS(natural_coords, X, dnds); Tensor3 J(natural_spatial_dimension, natural_spatial_dimension, natural_coords.cols()); // Computing the coordinates of the element in the natural space - auto && R = RDOFs.block(0, 0, spatial_dimension, spatial_dimension); + auto &&R = RDOFs.block(0, 0, spatial_dimension, spatial_dimension); Matrix T(B.size(1), B.size(1)); T.fill(0); for (Int i = 0; i < nb_nodes_per_element; ++i) { T.block(i * RDOFs.rows(), i * RDOFs.rows(), RDOFs.rows(), RDOFs.cols()) = RDOFs; } // Rotate to local basis auto x = (R * X).block(0, 0, natural_spatial_dimension, nb_nodes_per_element); ElementClass::computeJMat(natural_coords, x, J); ElementClass::computeShapeDerivatives(J, dnds, T, B); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template template void ShapeStructural::interpolateOnIntegrationPoints( - const Array & in_u, Array & out_uq, Int nb_dof, - GhostType ghost_type, const Array & filter_elements) const { + const Array &in_u, Array &out_uq, Int nb_dof, + GhostType ghost_type, const Array &filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(out_uq.getNbComponent() == nb_dof, "The output array shape is not correct"); auto itp_type = FEEngine::getInterpolationType(type); - const auto & shapes_ = shapes(itp_type, ghost_type); + const auto &shapes_ = shapes(itp_type, ghost_type); auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_nodes_per_element = ElementClass::getNbNodesPerElement(); auto nb_quad_points_per_element = integration_points(type, ghost_type).cols(); Array u_el(0, nb_nodes_per_element * nb_dof); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); auto nb_quad_points = nb_quad_points_per_element * u_el.size(); out_uq.resize(nb_quad_points); auto out_it = make_view(out_uq, nb_dof, 1, nb_quad_points_per_element).begin(); auto shapes_it = make_view(shapes_, nb_dof, nb_dof * nb_nodes_per_element, nb_quad_points_per_element) .begin(); auto u_it = make_view(u_el, nb_dof * nb_nodes_per_element, 1, nb_quad_points_per_element) .begin(); - for_each_element(nb_element, filter_elements, [&](auto && el) { - auto & uq = *out_it; - const auto & u = *u_it; - auto && N = shapes_it[el]; + for_each_element(nb_element, filter_elements, [&](auto &&el) { + auto &uq = *out_it; + const auto &u = *u_it; + auto &&N = shapes_it[el]; - for (auto && q : arange(uq.size(2))) { + for (auto &&q : arange(uq.size(2))) { uq(q) = N(q) * u(q); } ++out_it; ++u_it; }); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template template void ShapeStructural::gradientOnIntegrationPoints( - const Array & in_u, Array & out_nablauq, Int nb_dof, - GhostType ghost_type, const Array & filter_elements) const { + const Array &in_u, Array &out_nablauq, Int nb_dof, + GhostType ghost_type, const Array &filter_elements) const { AKANTU_DEBUG_IN(); auto itp_type = FEEngine::getInterpolationType(type); - const auto & shapesd = shapes_derivatives(itp_type, ghost_type); + const auto &shapesd = shapes_derivatives(itp_type, ghost_type); auto nb_element = mesh.getNbElement(type, ghost_type); auto element_dimension = ElementClass::getSpatialDimension(); auto nb_quad_points_per_element = integration_points(type, ghost_type).cols(); auto nb_nodes_per_element = ElementClass::getNbNodesPerElement(); Array u_el(0, nb_nodes_per_element * nb_dof); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); auto nb_quad_points = nb_quad_points_per_element * u_el.size(); out_nablauq.resize(nb_quad_points); auto out_it = make_view(out_nablauq, element_dimension, 1, nb_quad_points_per_element) .begin(); auto shapesd_it = make_view(shapesd, element_dimension, nb_dof * nb_nodes_per_element, nb_quad_points_per_element) .begin(); auto u_it = make_view(u_el, nb_dof * nb_nodes_per_element, 1, nb_quad_points_per_element) .begin(); - for_each_element(nb_element, filter_elements, [&](auto && el) { - auto & nablau = *out_it; - const auto & u = *u_it; + for_each_element(nb_element, filter_elements, [&](auto &&el) { + auto &nablau = *out_it; + const auto &u = *u_it; auto B = shapesd_it[el]; - for (auto && q : arange(nablau.size(2))) { + for (auto &&q : arange(nablau.size(2))) { nablau(q) = B(q) * u(q); } ++out_it; ++u_it; }); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <> template void ShapeStructural<_ek_structural>::computeBtD( - const Array & Ds, Array & BtDs, GhostType ghost_type, - const Array & filter_elements) const { + const Array &Ds, Array &BtDs, GhostType ghost_type, + const Array &filter_elements) const { auto itp_type = ElementClassProperty::interpolation_type; auto nb_stress = ElementClass::getNbStressComponents(); auto nb_dof_per_element = ElementClass::getNbDegreeOfFreedom() * mesh.getNbNodesPerElement(type); - const auto & shapes_derivatives = + const auto &shapes_derivatives = this->shapes_derivatives(itp_type, ghost_type); Array shapes_derivatives_filtered(0, shapes_derivatives.getNbComponent()); - auto && view = make_view(shapes_derivatives, nb_stress, nb_dof_per_element); + auto &&view = make_view(shapes_derivatives, nb_stress, nb_dof_per_element); auto B_it = view.begin(); auto B_end = view.end(); if (filter_elements != empty_filter) { FEEngine::filterElementalData(this->mesh, shapes_derivatives, shapes_derivatives_filtered, type, ghost_type, filter_elements); - auto && view = + auto &&view = make_view(shapes_derivatives_filtered, nb_stress, nb_dof_per_element); B_it = view.begin(); B_end = view.end(); } - for (auto && values : zip(range(B_it, B_end), make_view(Ds, nb_stress), - make_view(BtDs, BtDs.getNbComponent()))) { - const auto & B = std::get<0>(values); - const auto & D = std::get<1>(values); - auto & Bt_D = std::get<2>(values); + for (auto &&values : zip(range(B_it, B_end), make_view(Ds, nb_stress), + make_view(BtDs, BtDs.getNbComponent()))) { + const auto &B = std::get<0>(values); + const auto &D = std::get<1>(values); + auto &Bt_D = std::get<2>(values); Bt_D = B.transpose() * D; } } /* -------------------------------------------------------------------------- */ template <> template void ShapeStructural<_ek_structural>::computeNtb( - const Array & bs, Array & Ntbs, GhostType ghost_type, - const Array & filter_elements) const { + const Array &bs, Array &Ntbs, GhostType ghost_type, + const Array &filter_elements) const { constexpr auto itp_type = ElementClassProperty::interpolation_type; constexpr auto nb_dof = ElementClass::getNbDegreeOfFreedom(); auto nb_nodes_per_element = mesh.getNbNodesPerElement(type); - const auto & shapes = this->shapes(itp_type, ghost_type); + const auto &shapes = this->shapes(itp_type, ghost_type); Array shapes_filtered(0, shapes.getNbComponent()); - auto && view = make_view(shapes, nb_dof, nb_dof * nb_nodes_per_element); + auto &&view = make_view(shapes, nb_dof, nb_dof * nb_nodes_per_element); auto N_it = view.begin(); auto N_end = view.end(); if (filter_elements != empty_filter) { FEEngine::filterElementalData(this->mesh, shapes, shapes_filtered, type, ghost_type, filter_elements); - auto && view = + auto &&view = make_view(shapes_filtered, nb_dof, nb_dof * nb_nodes_per_element); N_it = view.begin(); N_end = view.end(); } - for (auto && values : zip(range(N_it, N_end), make_view(bs, nb_dof), - make_view(Ntbs, nb_dof * nb_nodes_per_element))) { - const auto & N = std::get<0>(values); - const auto & b = std::get<1>(values); - auto & Nt_b = std::get<2>(values); + for (auto &&values : zip(range(N_it, N_end), make_view(bs, nb_dof), + make_view(Ntbs, nb_dof * nb_nodes_per_element))) { + const auto &N = std::get<0>(values); + const auto &b = std::get<1>(values); + auto &Nt_b = std::get<2>(values); Nt_b = N.transpose() * b; } } } // namespace akantu //#endif /* AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_HH_ */ diff --git a/src/model/model.hh b/src/model/model.hh index a67771d03..5865b75c6 100644 --- a/src/model/model.hh +++ b/src/model/model.hh @@ -1,390 +1,390 @@ /** * @file model.hh * * @author Guillaume Anciaux * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Apr 09 2021 * * @brief Interface of a model * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_named_argument.hh" #include "fe_engine.hh" #include "mesh.hh" #include "model_options.hh" #include "model_solver.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef AKANTU_MODEL_HH_ #define AKANTU_MODEL_HH_ namespace akantu { class SynchronizerRegistry; class Parser; class DumperIOHelper; class DOFManager; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { class Model : public ModelSolver, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// Normal constructor where the DOFManager is created internally Model(Mesh & mesh, const ModelType & type, Int dim = _all_dimensions, const ID & id = "model"); /// Model constructor the the dof manager is created externally, for example /// in a ModelCoupler Model(Mesh & mesh, const ModelType & type, std::shared_ptr dof_manager, Int dim = _all_dimensions, const ID & id = "model"); ~Model() override; using FEEngineMap = std::map>; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: virtual void initFullImpl(const ModelOptions & options); public: template std::enable_if_t::value> initFull(pack &&... _pack) { switch (this->model_type) { #ifdef AKANTU_SOLID_MECHANICS case ModelType::_solid_mechanics_model: this->initFullImpl(SolidMechanicsModelOptions{ use_named_args, std::forward(_pack)...}); break; #endif #ifdef AKANTU_COHESIVE_ELEMENT case ModelType::_solid_mechanics_model_cohesive: this->initFullImpl(SolidMechanicsModelCohesiveOptions{ use_named_args, std::forward(_pack)...}); break; #endif #ifdef AKANTU_HEAT_TRANSFER case ModelType::_heat_transfer_model: this->initFullImpl(HeatTransferModelOptions{ use_named_args, std::forward(_pack)...}); break; #endif #ifdef AKANTU_PHASE_FIELD case ModelType::_phase_field_model: this->initFullImpl(PhaseFieldModelOptions{ use_named_args, std::forward(_pack)...}); break; #endif #ifdef AKANTU_EMBEDDED case ModelType::_embedded_model: this->initFullImpl(EmbeddedInterfaceModelOptions{ use_named_args, std::forward(_pack)...}); break; #endif #ifdef AKANTU_CONTACT_MECHANICS case ModelType::_contact_mechanics_model: this->initFullImpl(ContactMechanicsModelOptions{ use_named_args, std::forward(_pack)...}); break; #endif #ifdef AKANTU_MODEL_COUPLERS case ModelType::_coupler_solid_contact: this->initFullImpl(CouplerSolidContactOptions{ use_named_args, std::forward(_pack)...}); break; case ModelType::_coupler_solid_cohesive_contact: this->initFullImpl(CouplerSolidCohesiveContactOptions{ use_named_args, std::forward(_pack)...}); break; #endif default: this->initFullImpl(ModelOptions{use_named_args, std::forward(_pack)...}); } } template std::enable_if_t::value> initFull(pack &&... _pack) { this->initFullImpl(std::forward(_pack)...); } /// initialize a new solver if needed void initNewSolver(const AnalysisMethod & method); protected: /// get some default values for derived classes virtual std::tuple getDefaultSolverID(const AnalysisMethod & method) = 0; virtual void initModel(){}; virtual void initFEEngineBoundary(); /// function to print the containt of the class void printself(std::ostream & /*stream*/, int /*indent*/ = 0) const override{}; public: /* ------------------------------------------------------------------------ */ /* Access to the dumpable interface of the boundaries */ /* ------------------------------------------------------------------------ */ /// Dump the data for a given group void dumpGroup(const std::string & group_name); void dumpGroup(const std::string & group_name, const std::string & dumper_name); /// Dump the data for all boundaries void dumpGroup(); /// Set the directory for a given group void setGroupDirectory(const std::string & directory, const std::string & group_name); /// Set the directory for all boundaries void setGroupDirectory(const std::string & directory); /// Set the base name for a given group void setGroupBaseName(const std::string & basename, const std::string & group_name); /// Get the internal dumper of a given group DumperIOHelper & getGroupDumper(const std::string & group_name); /* ------------------------------------------------------------------------ */ /* Function for non local capabilities */ /* ------------------------------------------------------------------------ */ virtual void updateDataForNonLocalCriterion(__attribute__((unused)) ElementTypeMapReal & criterion) { AKANTU_TO_IMPLEMENT(); } protected: template void allocNodalField(std::unique_ptr> & array, Int nb_component, const ID & name) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get id of model AKANTU_GET_MACRO(ID, id, const ID &) /// get the number of surfaces AKANTU_GET_MACRO(Mesh, mesh, Mesh &) /// synchronize the boundary in case of parallel run virtual void synchronizeBoundaries(){}; /// return the fem object associated with a provided name inline FEEngine & getFEEngine(const ID & name = "") const; /// return the fem boundary object associated with a provided name virtual FEEngine & getFEEngineBoundary(const ID & name = ""); inline bool hasFEEngineBoundary(const ID & name = ""); /// register a fem object associated with name template inline void registerFEEngineObject(const std::string & name, Mesh & mesh, Int spatial_dimension); /// unregister a fem object associated with name inline void unRegisterFEEngineObject(const std::string & name); /// return the synchronizer registry SynchronizerRegistry & getSynchronizerRegistry(); /// return the fem object associated with a provided name template inline FEEngineClass & getFEEngineClass(std::string name = "") const; /// return the fem boundary object associated with a provided name template inline FEEngineClass & getFEEngineClassBoundary(std::string name = ""); /// Get the type of analysis method used AKANTU_GET_MACRO(AnalysisMethod, method, AnalysisMethod); /// return the dimension of the system space - AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt); + AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, Int); /* ------------------------------------------------------------------------ */ /* Pack and unpack hexlper functions */ /* ------------------------------------------------------------------------ */ public: inline Int getNbIntegrationPoints(const Array & elements, - const ID & fem_id = ID()) const; + const ID & fem_id = ID()) const; /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ void setTextModeToDumper(); virtual void addDumpGroupFieldToDumper(const std::string & field_id, std::shared_ptr field, DumperIOHelper & dumper); virtual void addDumpField(const std::string & field_id); virtual void addDumpFieldVector(const std::string & field_id); virtual void addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldTensor(const std::string & field_id); virtual void setBaseName(const std::string & field_id); virtual void setBaseNameToDumper(const std::string & dumper_name, const std::string & basename); virtual void addDumpGroupField(const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, ElementKind element_kind, bool padding_flag); virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, Int spatial_dimension, ElementKind element_kind, bool padding_flag); virtual void removeDumpGroupField(const std::string & field_id, const std::string & group_name); virtual void removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual std::shared_ptr createNodalFieldReal(const std::string & /*field_name*/, const std::string & /*group_name*/, bool /*padding_flag*/) { return nullptr; } virtual std::shared_ptr createNodalFieldInt(const std::string & /*field_name*/, - const std::string & /*group_name*/, - bool /*padding_flag*/) { + const std::string & /*group_name*/, + bool /*padding_flag*/) { return nullptr; } virtual std::shared_ptr createNodalFieldBool(const std::string & /*field_name*/, const std::string & /*group_name*/, bool /*padding_flag*/) { return nullptr; } virtual std::shared_ptr createElementalField( const std::string & /*field_name*/, const std::string & /*group_name*/, bool /*padding_flag*/, Int /*spatial_dimension*/, ElementKind /*kind*/) { return nullptr; } void setDirectory(const std::string & directory); void setDirectoryToDumper(const std::string & dumper_name, const std::string & directory); /* ------------------------------------------------------------------------ */ virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, Int step); virtual void dump(const std::string & dumper_name, Real time, Int step); /* ------------------------------------------------------------------------ */ virtual void dump(); virtual void dump(Int step); virtual void dump(Real time, Int step); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: friend std::ostream & operator<<(std::ostream & /*stream*/, const Model & /*_this*/); ID id; /// analysis method check the list in akantu::AnalysisMethod AnalysisMethod method; /// Mesh Mesh & mesh; /// Spatial dimension of the problem Int spatial_dimension; /// the main fem object present in all models FEEngineMap fems; /// the fem object present in all models for boundaries FEEngineMap fems_boundary; /// default fem object std::string default_fem; /// parser to the pointer to use Parser & parser; /// default ElementKind for dumper ElementKind dumper_default_element_kind{_ek_regular}; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Model & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "model_inline_impl.hh" #endif /* AKANTU_MODEL_HH_ */ diff --git a/src/model/phase_field/phase_field_model.cc b/src/model/phase_field/phase_field_model.cc index 09a47e559..be8c90e78 100644 --- a/src/model/phase_field/phase_field_model.cc +++ b/src/model/phase_field/phase_field_model.cc @@ -1,602 +1,602 @@ /** * @file phase_field_model.cc * * @author Mohit Pundir * * @date creation: Tue Sep 04 2018 * @date last modification: Wed Jun 23 2021 * * @brief Implementation of PhaseFieldModel class * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "phase_field_model.hh" #include "dumpable_inline_impl.hh" #include "element_synchronizer.hh" #include "fe_engine_template.hh" #include "generalized_trapezoidal.hh" #include "group_manager_inline_impl.hh" #include "integrator_gauss.hh" #include "mesh.hh" #include "parser.hh" #include "shape_lagrange.hh" /* -------------------------------------------------------------------------- */ #include "dumper_element_partition.hh" #include "dumper_elemental_field.hh" #include "dumper_internal_material_field.hh" #include "dumper_iohelper_paraview.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ -PhaseFieldModel::PhaseFieldModel(Mesh & mesh, Int dim, const ID & id, +PhaseFieldModel::PhaseFieldModel(Mesh &mesh, Int dim, const ID &id, ModelType model_type) : Model(mesh, model_type, dim, id), phasefield_index("phasefield index", id), phasefield_local_numbering("phasefield local numbering", id) { AKANTU_DEBUG_IN(); this->registerFEEngineObject("PhaseFieldFEEngine", mesh, Model::spatial_dimension); this->mesh.registerDumper("phase_field", id, true); this->mesh.addDumpMesh(mesh, Model::spatial_dimension, _not_ghost, _ek_regular); phasefield_selector = std::make_shared(phasefield_index); this->initDOFManager(); this->registerDataAccessor(*this); if (this->mesh.isDistributed()) { - auto & synchronizer = this->mesh.getElementSynchronizer(); + auto &synchronizer = this->mesh.getElementSynchronizer(); this->registerSynchronizer(synchronizer, SynchronizationTag::_pfm_damage); this->registerSynchronizer(synchronizer, SynchronizationTag::_pfm_driving); this->registerSynchronizer(synchronizer, SynchronizationTag::_pfm_history); this->registerSynchronizer(synchronizer, SynchronizationTag::_pfm_energy); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ PhaseFieldModel::~PhaseFieldModel() = default; /* -------------------------------------------------------------------------- */ -MatrixType PhaseFieldModel::getMatrixType(const ID & matrix_id) const { +MatrixType PhaseFieldModel::getMatrixType(const ID &matrix_id) const { if (matrix_id == "K") { return _symmetric; } return _mt_not_defined; } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::initModel() { - auto & fem = this->getFEEngine(); + auto &fem = this->getFEEngine(); fem.initShapeFunctions(_not_ghost); fem.initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ -void PhaseFieldModel::initFullImpl(const ModelOptions & options) { +void PhaseFieldModel::initFullImpl(const ModelOptions &options) { phasefield_index.initialize(mesh, _element_kind = _ek_not_defined, _default_value = UInt(-1), _with_nb_element = true); phasefield_local_numbering.initialize(mesh, _element_kind = _ek_not_defined, _with_nb_element = true); Model::initFullImpl(options); // initialize the phasefields if (!this->parser.getLastParsedFile().empty()) { this->instantiatePhaseFields(); this->initPhaseFields(); } this->initBC(*this, *damage, *external_force); } /* -------------------------------------------------------------------------- */ PhaseField & -PhaseFieldModel::registerNewPhaseField(const ParserSection & section) { +PhaseFieldModel::registerNewPhaseField(const ParserSection §ion) { std::string phase_name; std::string phase_type = section.getName(); std::string opt_param = section.getOption(); try { std::string tmp = section.getParameter("name"); phase_name = tmp; /** this can seam 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 phasefield of type \'" << phase_type << "\' in the input file has been defined without a name!"); } - PhaseField & phase = + PhaseField &phase = this->registerNewPhaseField(phase_name, phase_type, opt_param); phase.parseSection(section); return phase; } /* -------------------------------------------------------------------------- */ -PhaseField & PhaseFieldModel::registerNewPhaseField(const ID & phase_name, - const ID & phase_type, - const ID & opt_param) { +PhaseField &PhaseFieldModel::registerNewPhaseField(const ID &phase_name, + const ID &phase_type, + const ID &opt_param) { AKANTU_DEBUG_ASSERT(phasefields_names_to_id.find(phase_name) == phasefields_names_to_id.end(), "A phasefield with this name '" << phase_name << "' has already been registered. " << "Please use unique names for phasefields"); UInt phase_count = phasefields.size(); phasefields_names_to_id[phase_name] = phase_count; std::stringstream sstr_phase; sstr_phase << this->id << ":" << phase_count << ":" << phase_type; ID mat_id = sstr_phase.str(); std::unique_ptr phase = PhaseFieldFactory::getInstance().allocate( phase_type, opt_param, *this, mat_id); phasefields.push_back(std::move(phase)); return *(phasefields.back()); } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::instantiatePhaseFields() { ParserSection model_section; bool is_empty; std::tie(model_section, is_empty) = this->getParserSection(); if (not is_empty) { auto model_phasefields = model_section.getSubSections(ParserType::_phasefield); - for (const auto & section : model_phasefields) { + for (const auto §ion : model_phasefields) { this->registerNewPhaseField(section); } } auto sub_sections = this->parser.getSubSections(ParserType::_phasefield); - for (const auto & section : sub_sections) { + for (const auto §ion : sub_sections) { this->registerNewPhaseField(section); } if (phasefields.empty()) { AKANTU_EXCEPTION("No phasefields where instantiated for the model" << getID()); } are_phasefields_instantiated = true; } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::initPhaseFields() { AKANTU_DEBUG_ASSERT(phasefields.size() != 0, "No phasefield to initialize !"); if (!are_phasefields_instantiated) { instantiatePhaseFields(); } this->assignPhaseFieldToElements(); - for (auto & phasefield : phasefields) { + for (auto &phasefield : phasefields) { /// init internals properties phasefield->initPhaseField(); } this->synchronize(SynchronizationTag::_smm_init_mat); } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::assignPhaseFieldToElements( - const ElementTypeMapArray * filter) { + const ElementTypeMapArray *filter) { for_each_element( mesh, - [&](auto && element) { + [&](auto &&element) { Int phase_index = (*phasefield_selector)(element); AKANTU_DEBUG_ASSERT( - phase_index < phasefields.size(), + phase_index < Int(phasefields.size()), "The phasefield selector returned an index that does not exists"); phasefield_index(element) = phase_index; }, _element_filter = filter, _ghost_type = _not_ghost); for_each_element( mesh, - [&](auto && element) { + [&](auto &&element) { auto phase_index = phasefield_index(element); auto index = phasefields[phase_index]->addElement(element); phasefield_local_numbering(element) = index; }, _element_filter = filter, _ghost_type = _not_ghost); // synchronize the element phasefield arrays this->synchronize(SynchronizationTag::_material_id); } /* -------------------------------------------------------------------------- */ -void PhaseFieldModel::assembleMatrix(const ID & matrix_id) { +void PhaseFieldModel::assembleMatrix(const ID &matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } else { AKANTU_ERROR("Unknown Matrix ID for PhaseFieldModel : " << matrix_id); } } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::predictor() { // AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::corrector() { // AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType /*unused*/) { - DOFManager & dof_manager = this->getDOFManager(); + DOFManager &dof_manager = this->getDOFManager(); this->allocNodalField(this->damage, 1, "damage"); this->allocNodalField(this->external_force, 1, "external_force"); this->allocNodalField(this->internal_force, 1, "internal_force"); this->allocNodalField(this->blocked_dofs, 1, "blocked_dofs"); this->allocNodalField(this->previous_damage, 1, "previous_damage"); if (!dof_manager.hasDOFs("damage")) { dof_manager.registerDOFs("damage", *this->damage, _dst_nodal); dof_manager.registerBlockedDOFs("damage", *this->blocked_dofs); dof_manager.registerDOFsPrevious("damage", *this->previous_damage); } if (time_step_solver_type == TimeStepSolverType::_dynamic) { AKANTU_TO_IMPLEMENT(); } } /* -------------------------------------------------------------------------- */ -FEEngine & PhaseFieldModel::getFEEngineBoundary(const ID & name) { +FEEngine &PhaseFieldModel::getFEEngineBoundary(const ID &name) { return dynamic_cast(getFEEngineClassBoundary(name)); } /* -------------------------------------------------------------------------- */ std::tuple -PhaseFieldModel::getDefaultSolverID(const AnalysisMethod & method) { +PhaseFieldModel::getDefaultSolverID(const AnalysisMethod &method) { switch (method) { case _explicit_lumped_mass: { return std::make_tuple("explicit_lumped", TimeStepSolverType::_dynamic_lumped); } case _explicit_consistent_mass: { return std::make_tuple("explicit", TimeStepSolverType::_dynamic); } case _static: { return std::make_tuple("static", TimeStepSolverType::_static); } case _implicit_dynamic: { return std::make_tuple("implicit", TimeStepSolverType::_dynamic); } default: return std::make_tuple("unknown", TimeStepSolverType::_not_defined); } } /* -------------------------------------------------------------------------- */ -ModelSolverOptions PhaseFieldModel::getDefaultSolverOptions( - const TimeStepSolverType & type) const { +ModelSolverOptions +PhaseFieldModel::getDefaultSolverOptions(const TimeStepSolverType &type) const { ModelSolverOptions options; switch (type) { case TimeStepSolverType::_dynamic_lumped: { options.non_linear_solver_type = NonLinearSolverType::_lumped; options.integration_scheme_type["damage"] = IntegrationSchemeType::_central_difference; options.solution_type["damage"] = IntegrationScheme::_acceleration; break; } case TimeStepSolverType::_static: { options.non_linear_solver_type = NonLinearSolverType::_linear; options.integration_scheme_type["damage"] = IntegrationSchemeType::_pseudo_time; options.solution_type["damage"] = IntegrationScheme::_not_defined; break; } case TimeStepSolverType::_dynamic: { options.non_linear_solver_type = NonLinearSolverType::_newton_raphson; options.integration_scheme_type["damage"] = IntegrationSchemeType::_backward_euler; options.solution_type["damage"] = IntegrationScheme::_damage; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::beforeSolveStep() { - for (auto & phasefield : phasefields) { + for (auto &phasefield : phasefields) { phasefield->beforeSolveStep(); } } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::afterSolveStep(bool converged) { if (not converged) { return; } - for (auto && values : zip(*damage, *previous_damage)) { - auto & dam = std::get<0>(values); - auto & prev_dam = std::get<1>(values); + for (auto &&values : zip(*damage, *previous_damage)) { + auto &dam = std::get<0>(values); + auto &prev_dam = std::get<1>(values); dam -= prev_dam; prev_dam = dam; } } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::assembleStiffnessMatrix() { AKANTU_DEBUG_INFO("Assemble the new stiffness matrix"); if (!this->getDOFManager().hasMatrix("K")) { this->getDOFManager().getNewMatrix("K", getMatrixType("K")); } this->getDOFManager().zeroMatrix("K"); - for (auto & phasefield : phasefields) { + for (auto &phasefield : phasefields) { phasefield->assembleStiffnessMatrix(_not_ghost); } } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::assembleResidual() { this->assembleInternalForces(); this->getDOFManager().assembleToResidual("damage", *this->external_force, 1); this->getDOFManager().assembleToResidual("damage", *this->internal_force, 1); } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::assembleInternalForces() { AKANTU_DEBUG_INFO("Assemble the internal forces"); this->internal_force->zero(); // communicate the driving forces AKANTU_DEBUG_INFO("Send data for residual assembly"); this->asynchronousSynchronize(SynchronizationTag::_pfm_driving); // assemble the forces due to local driving forces AKANTU_DEBUG_INFO("Assemble residual for local elements"); - for (auto & phasefield : phasefields) { + for (auto &phasefield : phasefields) { phasefield->assembleInternalForces(_not_ghost); } // finalize communications AKANTU_DEBUG_INFO("Wait distant driving forces"); this->waitEndSynchronize(SynchronizationTag::_pfm_driving); // assemble the residual due to ghost elements AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::assembleLumpedMatrix(const ID & /*matrix_id*/) {} /* -------------------------------------------------------------------------- */ -void PhaseFieldModel::setTimeStep(Real time_step, const ID & solver_id) { +void PhaseFieldModel::setTimeStep(Real time_step, const ID &solver_id) { Model::setTimeStep(time_step, solver_id); this->mesh.getDumper("phase_field").setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ -Int PhaseFieldModel::getNbData(const Array & elements, - const SynchronizationTag & tag) const { +Int PhaseFieldModel::getNbData(const Array &elements, + const SynchronizationTag &tag) const { Int size = 0; Int nb_nodes_per_element = 0; - for (const Element & el : elements) { + for (const Element &el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch (tag) { case SynchronizationTag::_pfm_damage: { size += nb_nodes_per_element * sizeof(Real); // damage break; } case SynchronizationTag::_pfm_driving: { size += getNbIntegrationPoints(elements) * sizeof(Real); break; } case SynchronizationTag::_pfm_history: { size += getNbIntegrationPoints(elements) * sizeof(Real); break; } case SynchronizationTag::_pfm_energy: { size += getNbIntegrationPoints(elements) * sizeof(Real); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } return size; } /* -------------------------------------------------------------------------- */ void PhaseFieldModel::packData(__attribute__((unused)) - CommunicationBuffer & buffer, + CommunicationBuffer &buffer, __attribute__((unused)) - const Array & elements, + const Array &elements, __attribute__((unused)) - const SynchronizationTag & tag) const {} + const SynchronizationTag &tag) const {} /* -------------------------------------------------------------------------- */ void PhaseFieldModel::unpackData(__attribute__((unused)) - CommunicationBuffer & buffer, + CommunicationBuffer &buffer, __attribute__((unused)) - const Array & elements, + const Array &elements, __attribute__((unused)) - const SynchronizationTag & tag) {} + const SynchronizationTag &tag) {} /* -------------------------------------------------------------------------- */ -Int PhaseFieldModel::getNbData(const Array & indexes, - const SynchronizationTag & tag) const { +Int PhaseFieldModel::getNbData(const Array &indexes, + const SynchronizationTag &tag) const { UInt size = 0; UInt nb_nodes = indexes.size(); switch (tag) { case SynchronizationTag::_pfm_damage: { size += nb_nodes * sizeof(Real); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } return size; } /* -------------------------------------------------------------------------- */ -void PhaseFieldModel::packData(CommunicationBuffer & buffer, - const Array & indexes, - const SynchronizationTag & tag) const { +void PhaseFieldModel::packData(CommunicationBuffer &buffer, + const Array &indexes, + const SynchronizationTag &tag) const { for (auto index : indexes) { switch (tag) { case SynchronizationTag::_pfm_damage: { buffer << (*damage)(index); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } } } /* -------------------------------------------------------------------------- */ -void PhaseFieldModel::unpackData(CommunicationBuffer & buffer, - const Array & indexes, - const SynchronizationTag & tag) { +void PhaseFieldModel::unpackData(CommunicationBuffer &buffer, + const Array &indexes, + const SynchronizationTag &tag) { for (auto index : indexes) { switch (tag) { case SynchronizationTag::_pfm_damage: { buffer >> (*damage)(index); break; } default: { AKANTU_ERROR("Unknown ghost synchronization tag : " << tag); } } } } /* -------------------------------------------------------------------------- */ std::shared_ptr -PhaseFieldModel::createNodalFieldBool(const std::string & field_name, - const std::string & group_name, +PhaseFieldModel::createNodalFieldBool(const std::string &field_name, + const std::string &group_name, bool /*unused*/) { std::map *> uint_nodal_fields; uint_nodal_fields["blocked_dofs"] = blocked_dofs.get(); return mesh.createNodalField(uint_nodal_fields[field_name], group_name); std::shared_ptr field; return field; } /* -------------------------------------------------------------------------- */ std::shared_ptr -PhaseFieldModel::createNodalFieldReal(const std::string & field_name, - const std::string & group_name, +PhaseFieldModel::createNodalFieldReal(const std::string &field_name, + const std::string &group_name, bool /*unused*/) { std::map *> real_nodal_fields; real_nodal_fields["damage"] = damage.get(); real_nodal_fields["external_force"] = external_force.get(); real_nodal_fields["internal_force"] = internal_force.get(); return mesh.createNodalField(real_nodal_fields[field_name], group_name); std::shared_ptr field; return field; } /* -------------------------------------------------------------------------- */ std::shared_ptr PhaseFieldModel::createElementalField( - const std::string & field_name, const std::string & group_name, + const std::string &field_name, const std::string &group_name, bool /*unused*/, Int /*unused*/, ElementKind element_kind) { if (field_name == "partitions") { return mesh.createElementalField( mesh.getConnectivities(), group_name, this->spatial_dimension, element_kind); } std::shared_ptr field; return field; } /* -------------------------------------------------------------------------- */ -void PhaseFieldModel::printself(std::ostream & stream, int indent) const { +void PhaseFieldModel::printself(std::ostream &stream, int indent) const { std::string space(indent, AKANTU_INDENT); stream << space << "Phase Field Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << Model::spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; damage->printself(stream, indent + 2); external_force->printself(stream, indent + 2); internal_force->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + phasefield information [" << std::endl; stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } } // namespace akantu diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 33bcecac5..4add7110a 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1144 +1,1146 @@ /** * @file material.cc * * @author Guillaume Anciaux * @author Fabian Barras * @author Aurelia Isabel Cuba Ramos * @author Lucas Frerot * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Tue Jul 27 2010 * @date last modification: Fri Apr 09 2021 * * @brief Implementation of the common part of the material class * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "mesh_iterators.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Parsable(ParserType::_material, id), id(id), fem(model.getFEEngine()), model(model), spatial_dimension(this->model.getSpatialDimension()), element_filter("element_filter", id), stress("stress", *this), eigengradu("eigen_grad_u", *this), gradu("grad_u", *this), green_strain("green_strain", *this), piola_kirchhoff_2("piola_kirchhoff_2", *this), potential_energy("potential_energy", *this), interpolation_inverse_coordinates("interpolation inverse coordinates", *this), interpolation_points_matrices("interpolation points matrices", *this), eigen_grad_u(model.getSpatialDimension(), model.getSpatialDimension()) { eigen_grad_u.fill(0.); this->registerParam("eigen_grad_u", eigen_grad_u, _pat_parsable, "EigenGradU"); /// for each connectivity types allocate the element filer array of the /// material element_filter.initialize(model.getMesh(), _spatial_dimension = spatial_dimension, _element_kind = _ek_regular); this->initialize(); } /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, Int dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Parsable(ParserType::_material, id), id(id), fem(fe_engine), model(model), spatial_dimension(dim), element_filter("element_filter", id), stress("stress", *this, dim, fe_engine, this->element_filter), eigengradu("eigen_grad_u", *this, dim, fe_engine, this->element_filter), gradu("gradu", *this, dim, fe_engine, this->element_filter), green_strain("green_strain", *this, dim, fe_engine, this->element_filter), piola_kirchhoff_2("piola_kirchhoff_2", *this, dim, fe_engine, this->element_filter), potential_energy("potential_energy", *this, dim, fe_engine, this->element_filter), interpolation_inverse_coordinates("interpolation inverse_coordinates", *this, dim, fe_engine, this->element_filter), interpolation_points_matrices("interpolation points matrices", *this, dim, fe_engine, this->element_filter), eigen_grad_u(dim, dim) { eigen_grad_u.fill(0.); element_filter.initialize(mesh, _spatial_dimension = spatial_dimension, _element_kind = _ek_regular); this->initialize(); } /* -------------------------------------------------------------------------- */ Material::~Material() = default; /* -------------------------------------------------------------------------- */ void Material::initialize() { registerParam("rho", rho, Real(0.), _pat_parsable | _pat_modifiable, "Density"); registerParam("name", name, std::string(), _pat_parsable | _pat_readable); registerParam("finite_deformation", finite_deformation, false, _pat_parsable | _pat_readable, "Is finite deformation"); registerParam("inelastic_deformation", inelastic_deformation, false, _pat_internal, "Is inelastic deformation"); /// allocate gradu stress for local elements eigengradu.initialize(spatial_dimension * spatial_dimension); gradu.initialize(spatial_dimension * spatial_dimension); stress.initialize(spatial_dimension * spatial_dimension); potential_energy.initialize(1); this->model.registerEventHandler(*this); } /* -------------------------------------------------------------------------- */ void Material::initMaterial() { AKANTU_DEBUG_IN(); if (finite_deformation) { this->piola_kirchhoff_2.initialize(spatial_dimension * spatial_dimension); this->piola_kirchhoff_2.initializeHistory(); this->green_strain.initialize(spatial_dimension * spatial_dimension); } this->stress.initializeHistory(); this->gradu.initializeHistory(); this->resizeInternals(); auto dim = spatial_dimension; for (const auto & type : element_filter.elementTypes(_element_kind = _ek_regular)) { for (auto & eigen_gradu : make_view(eigengradu(type), dim, dim)) { eigen_gradu = eigen_grad_u; } } is_init = true; updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (auto pair : internal_vectors_real) { if (pair.second->hasHistory()) { pair.second->saveCurrentValues(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::restorePreviousState() { AKANTU_DEBUG_IN(); for (auto pair : internal_vectors_real) { if (pair.second->hasHistory()) { pair.second->restorePreviousValues(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the internal forces by assembling @f$\int_{e} \sigma_e \frac{\partial * \varphi}{\partial X} dX @f$ * * @param[in] ghost_type compute the internal forces for _ghost or _not_ghost * element */ void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); Int spatial_dimension = model.getSpatialDimension(); if (not finite_deformation) { auto & internal_force = model.getInternalForce(); // Mesh & mesh = fem.getMesh(); for (auto && type : element_filter.elementTypes(spatial_dimension, ghost_type)) { auto && elem_filter = element_filter(type, ghost_type); auto nb_element = elem_filter.size(); if (nb_element == 0) { continue; } const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by /// @f$\mathbf{B}^t \mathbf{\sigma}_q@f$ auto * sigma_dphi_dx = new Array(nb_element * nb_quadrature_points, size_of_shapes_derivatives, "sigma_x_dphi_/_dX"); fem.computeBtD(stress(type, ghost_type), *sigma_dphi_dx, type, ghost_type, elem_filter); /** * compute @f$\int \sigma * \frac{\partial \varphi}{\partial X}dX@f$ by * @f$ \sum_q \mathbf{B}^t * \mathbf{\sigma}_q \overline w_q J_q@f$ */ auto * int_sigma_dphi_dx = new Array(nb_element, nb_nodes_per_element * spatial_dimension, "int_sigma_x_dphi_/_dX"); fem.integrate(*sigma_dphi_dx, *int_sigma_dphi_dx, size_of_shapes_derivatives, type, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble model.getDOFManager().assembleElementalArrayLocalArray( *int_sigma_dphi_dx, internal_force, type, ghost_type, -1, elem_filter); delete int_sigma_dphi_dx; } } else { switch (spatial_dimension) { case 1: this->assembleInternalForces<1>(ghost_type); break; case 2: this->assembleInternalForces<2>(ghost_type); break; case 3: this->assembleInternalForces<3>(ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stress from the gradu * * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); auto spatial_dimension = model.getSpatialDimension(); for (const auto & type : element_filter.elementTypes(spatial_dimension, ghost_type)) { auto & elem_filter = element_filter(type, ghost_type); if (elem_filter.empty()) { continue; } auto & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, spatial_dimension, type, ghost_type, elem_filter); gradu_vect -= eigengradu(type, ghost_type); /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$ computeStress(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllCauchyStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(finite_deformation, "The Cauchy stress can only be " "computed if you are working in " "finite deformation."); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { switch (spatial_dimension) { case 1: this->StoCauchy<1>(type, ghost_type); break; case 2: this->StoCauchy<2>(type, ghost_type); break; case 3: this->StoCauchy<3>(type, ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::StoCauchy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); for (auto && data : zip(make_view(this->gradu(el_type, ghost_type)), make_view(this->piola_kirchhoff_2(el_type, ghost_type)), make_view(this->stress(el_type, ghost_type)))) { auto && grad_u = std::get<0>(data); auto && piola = std::get<1>(data); auto && sigma = std::get<2>(data); this->StoCauchy(gradUToF(grad_u), piola, sigma); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::setToSteadyState(GhostType ghost_type) { AKANTU_DEBUG_IN(); const auto & displacement = model.getDisplacement(); // resizeInternalArray(gradu); auto spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { auto & elem_filter = element_filter(type, ghost_type); auto & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(displacement, gradu_vect, spatial_dimension, type, ghost_type, elem_filter); setToSteadyState(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stiffness matrix by assembling @f$\int_{\omega} B^t \times D * \times B d\omega @f$ * * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); auto spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { if (finite_deformation) { switch (spatial_dimension) { case 1: { assembleStiffnessMatrixNL<1>(type, ghost_type); assembleStiffnessMatrixL2<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrixNL<2>(type, ghost_type); assembleStiffnessMatrixL2<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrixNL<3>(type, ghost_type); assembleStiffnessMatrixL2<3>(type, ghost_type); break; } } } else { switch (spatial_dimension) { case 1: { assembleStiffnessMatrix<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrix<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrix<3>(type, ghost_type); break; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrix(ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const auto & elem_filter = element_filter(type, ghost_type); if (elem_filter.empty()) { AKANTU_DEBUG_OUT(); return; } // const Array & shapes_derivatives = // fem.getShapesDerivatives(type, ghost_type); auto & gradu_vect = gradu(type, ghost_type); auto nb_element = elem_filter.size(); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); auto tangent_size = getTangentStiffnessVoigtSize(dim); auto tangent_stiffness_matrix = std::make_unique>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->zero(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto bt_d_b_size = dim * nb_nodes_per_element; auto bt_d_b = std::make_unique>( nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); fem.computeBtDB(*tangent_stiffness_matrix, *bt_d_b, 4, type, ghost_type, elem_filter); /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto K_e = std::make_unique>(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrixNL(ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const auto & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); auto & elem_filter = element_filter(type, ghost_type); // Array & gradu_vect = delta_gradu(type, ghost_type); auto nb_element = elem_filter.size(); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); auto shapes_derivatives_filtered = std::make_unique>( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto bt_s_b_size = dim * nb_nodes_per_element; auto bt_s_b = std::make_unique>( nb_element * nb_quadrature_points, bt_s_b_size * bt_s_b_size, "B^t*D*B"); auto piola_matrix_size = getCauchyStressMatrixSize(dim); Matrix B(piola_matrix_size, bt_s_b_size); Matrix S(piola_matrix_size, piola_matrix_size); for (auto && data : zip(make_view(*bt_s_b, bt_s_b_size, bt_s_b_size), make_view(piola_kirchhoff_2(type, ghost_type), dim, dim), make_view(*shapes_derivatives_filtered, spatial_dimension, nb_nodes_per_element))) { auto && Bt_S_B = std::get<0>(data); auto && Piola_kirchhoff_matrix = std::get<1>(data); auto && shapes_derivatives = std::get<2>(data); setCauchyStressMatrix(Piola_kirchhoff_matrix, S); VoigtHelper::transferBMatrixToBNL(shapes_derivatives, B, nb_nodes_per_element); Bt_S_B = B.transpose() * S * B; } /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto K_e = std::make_unique>(nb_element, bt_s_b_size * bt_s_b_size, "K_e"); fem.integrate(*bt_s_b, *K_e, bt_s_b_size * bt_s_b_size, type, ghost_type, elem_filter); model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrixL2(ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const auto & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); auto & elem_filter = element_filter(type, ghost_type); auto & gradu_vect = gradu(type, ghost_type); auto nb_element = elem_filter.size(); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); constexpr auto tangent_size = getTangentStiffnessVoigtSize(dim); auto tangent_stiffness_matrix = std::make_unique>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->zero(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); auto shapes_derivatives_filtered = std::make_unique>( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto bt_d_b_size = dim * nb_nodes_per_element; auto bt_d_b = std::make_unique>( nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix B(tangent_size, bt_d_b_size); Matrix B2(tangent_size, bt_d_b_size); for (auto && data : zip(make_view(*bt_d_b, bt_d_b_size, bt_d_b_size), make_view(gradu_vect), make_view(*tangent_stiffness_matrix), make_view(*shapes_derivatives_filtered, dim, nb_nodes_per_element))) { auto && Bt_D_B = std::get<0>(data); auto && grad_u = std::get<1>(data); auto && D = std::get<2>(data); auto && shapes_derivative = std::get<3>(data); // transferBMatrixToBL1 (*shapes_derivatives_filtered_it, B, // nb_nodes_per_element); VoigtHelper::transferBMatrixToSymVoigtBMatrix(shapes_derivative, B, nb_nodes_per_element); VoigtHelper::transferBMatrixToBL2(shapes_derivative, grad_u, B2, nb_nodes_per_element); B += B2; Bt_D_B = B.transpose() * D * B; } /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto K_e = std::make_unique>(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & internal_force = model.getInternalForce(); auto & mesh = fem.getMesh(); for (auto type : element_filter.elementTypes(_ghost_type = ghost_type)) { const auto & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); auto & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; auto size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); auto nb_element = elem_filter.size(); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); auto shapesd_filtered = std::make_unique>( nb_element, size_of_shapes_derivatives, "filtered shapesd"); FEEngine::filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); // Set stress vectors auto stress_size = getTangentStiffnessVoigtSize(dim); auto bt_s_size = dim * nb_nodes_per_element; auto bt_s = std::make_unique>(nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); Matrix B_tensor(stress_size, bt_s_size); Matrix B2_tensor(stress_size, bt_s_size); for (auto && data : zip(make_view(this->gradu(type, ghost_type)), make_view(this->piola_kirchhoff_2(type, ghost_type)), make_view(*bt_s, bt_s_size), make_view(*shapesd_filtered, dim, nb_nodes_per_element))) { auto && grad_u = std::get<0>(data); auto && S = std::get<1>(data); auto && r = std::get<2>(data); auto && shapes_derivative = std::get<3>(data); VoigtHelper::transferBMatrixToSymVoigtBMatrix( shapes_derivative, B_tensor, nb_nodes_per_element); VoigtHelper::transferBMatrixToBL2(shapes_derivative, grad_u, B2_tensor, nb_nodes_per_element); B_tensor += B2_tensor; r = B_tensor.transpose() * Material::stressToVoigt(S); } /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto r_e = std::make_unique>(nb_element, bt_s_size, "r_e"); fem.integrate(*bt_s, *r_e, bt_s_size, type, ghost_type, elem_filter); model.getDOFManager().assembleElementalArrayLocalArray( *r_e, internal_force, type, ghost_type, -1., elem_filter); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergyByElements() { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { computePotentialEnergy(type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergy(ElementType) { AKANTU_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real epot = 0.; computePotentialEnergyByElements(); /// integrate the potential energy for each type of elements for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { epot += fem.integrate(potential_energy(type, _not_ghost), type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy(ElementType type, Int index) { return getPotentialEnergy({type, index, _not_ghost}); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy(const Element & element) { AKANTU_DEBUG_IN(); Real epot = 0.; Vector epot_on_quad_points(fem.getNbIntegrationPoints(element.type)); computePotentialEnergyByElement(element, epot_on_quad_points); epot = fem.integrate(epot_on_quad_points, {element.type, element_filter(element.type)(element.element), _not_ghost}); AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(const std::string & type) { AKANTU_DEBUG_IN(); if (type == "potential") { return getPotentialEnergy(); } AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(const std::string & energy_id, const Element & element) { AKANTU_DEBUG_IN(); if (energy_id == "potential") { return getPotentialEnergy(element); } AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ void Material::initElementalFieldInterpolation( const ElementTypeMapArray & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); this->fem.initElementalFieldInterpolationFromIntegrationPoints( interpolation_points_coordinates, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, &(this->element_filter)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(ElementTypeMapArray & result, const GhostType ghost_type) { this->fem.interpolateElementalFieldFromIntegrationPoints( this->stress, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, result, ghost_type, &(this->element_filter)); } /* -------------------------------------------------------------------------- */ void Material::interpolateStressOnFacets( ElementTypeMapArray & result, ElementTypeMapArray & by_elem_result, const GhostType ghost_type) { interpolateStress(by_elem_result, ghost_type); auto stress_size = this->stress.getNbComponent(); const auto & mesh = this->model.getMesh(); const auto & mesh_facets = mesh.getMeshFacets(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { auto & elem_fil = element_filter(type, ghost_type); auto & by_elem_res = by_elem_result(type, ghost_type); auto nb_element_full = mesh.getNbElement(type, ghost_type); auto nb_interpolation_points_per_elem = by_elem_res.size() / nb_element_full; const auto & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); auto type_facet = Mesh::getFacetType(type); auto nb_facet_per_elem = facet_to_element.getNbComponent(); auto nb_quad_per_facet = nb_interpolation_points_per_elem / nb_facet_per_elem; Element element_for_comparison{type, 0, ghost_type}; const Array> * element_to_facet = nullptr; - auto current_ghost_type = _casper; - Array::matrix_iterator result_vec_it; + auto current_ghost_type = _not_ghost; + auto result_vec_it = + make_view(result(type_facet, current_ghost_type), stress_size, 2) + .begin(); auto result_it = make_view(by_elem_res, stress_size, nb_interpolation_points_per_elem) .begin(); for (auto global_el : elem_fil) { element_for_comparison.element = global_el; for (Int f = 0; f < nb_facet_per_elem; ++f) { auto facet_elem = facet_to_element(global_el, f); auto global_facet = facet_elem.element; if (facet_elem.ghost_type != current_ghost_type) { current_ghost_type = facet_elem.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( type_facet, current_ghost_type); result_vec_it = make_view(result(type_facet, current_ghost_type), stress_size, 2) .begin(); } auto is_second_element = ((*element_to_facet)(global_facet)[0] != element_for_comparison); for (Int q = 0; q < nb_quad_per_facet; ++q) { auto && result_local = result_vec_it[global_facet * nb_quad_per_facet + q]( is_second_element); result_local = result_it[global_el](f * nb_quad_per_facet + q); } } } } } /* -------------------------------------------------------------------------- */ void Material::addElements(const Array & elements_to_add) { AKANTU_DEBUG_IN(); UInt mat_id = model.getMaterialIndex(name); for (const auto & element : elements_to_add) { auto index = this->addElement(element); model.material_index(element) = mat_id; model.material_local_numbering(element) = index; } this->resizeInternals(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::removeElements(const Array & elements_to_remove) { AKANTU_DEBUG_IN(); auto el_begin = elements_to_remove.begin(); auto el_end = elements_to_remove.end(); if (elements_to_remove.empty()) { return; } auto & mesh = this->model.getMesh(); ElementTypeMapArray material_local_new_numbering( "remove mat filter elem", id); material_local_new_numbering.initialize( mesh, _element_filter = &element_filter, _element_kind = _ek_not_defined, _with_nb_element = true); ElementTypeMapArray element_filter_tmp("element_filter_tmp", id); element_filter_tmp.initialize(mesh, _element_filter = &element_filter, _element_kind = _ek_not_defined); ElementTypeMap new_ids, element_ids; for_each_element( mesh, [&](auto && el) { if (not new_ids(el.type, el.ghost_type)) { element_ids(el.type, el.ghost_type) = 0; } auto & element_id = element_ids(el.type, el.ghost_type); auto l_el = Element{el.type, element_id, el.ghost_type}; if (std::find(el_begin, el_end, el) != el_end) { material_local_new_numbering(l_el) = UInt(-1); return; } element_filter_tmp(el.type, el.ghost_type).push_back(el.element); if (not new_ids(el.type, el.ghost_type)) { new_ids(el.type, el.ghost_type) = 0; } auto & new_id = new_ids(el.type, el.ghost_type); material_local_new_numbering(l_el) = new_id; model.material_local_numbering(el) = new_id; ++new_id; ++element_id; }, _element_filter = &element_filter, _element_kind = _ek_not_defined); for (auto ghost_type : ghost_types) { for (const auto & type : element_filter.elementTypes( _ghost_type = ghost_type, _element_kind = _ek_not_defined)) { element_filter(type, ghost_type) .copy(element_filter_tmp(type, ghost_type)); } } for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto it = internal_vectors_int.begin(); it != internal_vectors_int.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::resizeInternals() { AKANTU_DEBUG_IN(); for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { it->second->resize(); } for (auto it = internal_vectors_int.begin(); it != internal_vectors_int.end(); ++it) { it->second->resize(); } for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) { it->second->resize(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::onElementsAdded(const Array & /*unused*/, const NewElementsEvent & /*unused*/) { this->resizeInternals(); } /* -------------------------------------------------------------------------- */ void Material::onElementsRemoved( const Array & element_list, const ElementTypeMapArray & new_numbering, [[gnu::unused]] const RemovedElementsEvent & event) { auto my_num = model.getInternalIndexFromID(getID()); ElementTypeMapArray material_local_new_numbering( "remove mat filter elem", getID()); auto el_begin = element_list.begin(); auto el_end = element_list.end(); for (auto && gt : ghost_types) { for (auto && type : new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) { if (not element_filter.exists(type, gt) || element_filter(type, gt).empty()) { continue; } auto & elem_filter = element_filter(type, gt); auto & mat_indexes = this->model.material_index(type, gt); auto & mat_loc_num = this->model.material_local_numbering(type, gt); auto nb_element = this->model.getMesh().getNbElement(type, gt); // all materials will resize of the same size... mat_indexes.resize(nb_element); mat_loc_num.resize(nb_element); if (!material_local_new_numbering.exists(type, gt)) { material_local_new_numbering.alloc(elem_filter.size(), 1, type, gt); } auto & mat_renumbering = material_local_new_numbering(type, gt); const auto & renumbering = new_numbering(type, gt); Array elem_filter_tmp; UInt ni = 0; Element el{type, 0, gt}; for (auto && data : enumerate(elem_filter)) { el.element = std::get<1>(data); if (std::find(el_begin, el_end, el) == el_end) { auto new_el = renumbering(el.element); AKANTU_DEBUG_ASSERT(new_el != -1, "A not removed element as been badly renumbered"); elem_filter_tmp.push_back(new_el); mat_renumbering(std::get<0>(data)) = ni; mat_indexes(new_el) = my_num; mat_loc_num(new_el) = ni; ++ni; } else { mat_renumbering(std::get<0>(data)) = -1; } } elem_filter.resize(elem_filter_tmp.size()); elem_filter.copy(elem_filter_tmp); } } for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto it = internal_vectors_int.begin(); it != internal_vectors_int.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } } /* -------------------------------------------------------------------------- */ void Material::beforeSolveStep() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::afterSolveStep(bool converged) { if (not converged) { this->restorePreviousState(); return; } for (const auto & type : element_filter.elementTypes( _all_dimensions, _not_ghost, _ek_not_defined)) { this->updateEnergies(type); } } /* -------------------------------------------------------------------------- */ void Material::onDamageIteration() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::onDamageUpdate() { for (const auto & type : element_filter.elementTypes( _all_dimensions, _not_ghost, _ek_not_defined)) { this->updateEnergiesAfterDamage(type); } } /* -------------------------------------------------------------------------- */ void Material::onDump() { if (this->isFiniteDeformation()) { this->computeAllCauchyStresses(_not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::printself(std::ostream & stream, int indent) const { std::string space(indent, AKANTU_INDENT); std::string type = getID().substr(getID().find_last_of(':') + 1); stream << space << "Material " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /// extrapolate internal values void Material::extrapolateInternal(const ID & id, const Element & element, const Matrix & /*point*/, Matrix & extrapolated) { if (this->isInternal(id, element.kind())) { auto name = this->getID() + ":" + id; auto nb_quads = this->internal_vectors_real[name]->getFEEngine().getNbIntegrationPoints( element.type, element.ghost_type); const auto & internal = this->getArray(id, element.type, element.ghost_type); auto nb_component = internal.getNbComponent(); auto internal_it = make_view(internal, nb_component, nb_quads).begin(); auto local_element = this->convertToLocalElement(element); /// instead of really extrapolating, here the value of the first GP /// is copied into the result vector. This works only for linear /// elements /// @todo extrapolate!!!! AKANTU_DEBUG_WARNING("This is a fix, values are not truly extrapolated"); auto && values = internal_it[local_element.element]; Int index = 0; Vector tmp(nb_component); for (Int j = 0; j < values.cols(); ++j) { tmp = values(j); if (tmp.norm() > 0) { index = j; break; } } for (Int i = 0; i < extrapolated.size(); ++i) { extrapolated(i) = values(index); } } else { extrapolated.fill(0.); } } /* -------------------------------------------------------------------------- */ void Material::applyEigenGradU(const Matrix & prescribed_eigen_grad_u, const GhostType ghost_type) { for (auto && type : element_filter.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { if (element_filter(type, ghost_type).empty()) { continue; } for (auto & eigengradu : make_view(this->eigengradu(type, ghost_type), spatial_dimension, spatial_dimension)) { eigengradu = prescribed_eigen_grad_u; } } } /* -------------------------------------------------------------------------- */ MaterialFactory & Material::getFactory() { return MaterialFactory::getInstance(); } } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_damage/material_anisotropic_damage_tmpl.hh b/src/model/solid_mechanics/materials/material_damage/material_anisotropic_damage_tmpl.hh index ae0389289..a4a132dbf 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_anisotropic_damage_tmpl.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_anisotropic_damage_tmpl.hh @@ -1,377 +1,377 @@ /** * @file material_anisotropic_damage_tmpl.hh * * @author Emil Gallyamov * @author Nicolas Richart * * @date creation: Wed Jul 03 2019 * @date last modification: Fri Jul 24 2020 * * @brief Base class for anisotropic damage materials * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "material_anisotropic_damage.hh" /* -------------------------------------------------------------------------- */ #ifndef AKANTU_MATERIAL_ANISOTROPIC_DAMAGE_TMPL_HH_ #define AKANTU_MATERIAL_ANISOTROPIC_DAMAGE_TMPL_HH_ namespace akantu { struct EmptyIteratorContainer { using size_type = std::size_t; struct iterator { - auto &operator++() { return *this; } + auto & operator++() { return *this; } Real operator*() { return 0; } bool operator!=(const iterator & /*unused*/) const { return true; } bool operator==(const iterator & /*unused*/) const { return false; } }; auto begin() const // NOLINT(readability-convert-member-functions-to-static) { return iterator(); } auto end() const // NOLINT(readability-convert-member-functions-to-static) { return iterator(); } }; } // namespace akantu namespace std { template <> struct iterator_traits<::akantu::EmptyIteratorContainer::iterator> { using iterator_category = forward_iterator_tag; using value_type = akantu::Real; using difference_type = std::ptrdiff_t; using pointer = akantu::Real *; using reference = akantu::Real &; }; } // namespace std namespace akantu { namespace { -template -void tensorPlus_(const Eigen::MatrixBase &A, Op &&oper) { - Vector A_eigs; - A.eig(A_eigs); + template + void tensorPlus_(const Eigen::MatrixBase & A, Op && oper) { + Vector A_eigs; + A.eig(A_eigs); - for (auto &ap : A_eigs) { - oper(ap); + for (auto & ap : A_eigs) { + oper(ap); + } } -} -template auto tensorPlus2(const Eigen::MatrixBase &A) { - Real square = 0; - tensorPlus_(A, [&](Real eig) { - eig = std::max(eig, 0.); - square += eig * eig; - }); + template auto tensorPlus2(const Eigen::MatrixBase & A) { + Real square = 0; + tensorPlus_(A, [&](Real eig) { + eig = std::max(eig, 0.); + square += eig * eig; + }); - return square; -} + return square; + } -template -auto tensorPlusTrace(const Eigen::MatrixBase &A) { - Real trace_plus = 0.; - Real trace_minus = 0.; - tensorPlus_(A, [&](Real eig) { - trace_plus += std::max(eig, 0.); - trace_minus += std::min(eig, 0.); - }); + template + auto tensorPlusTrace(const Eigen::MatrixBase & A) { + Real trace_plus = 0.; + Real trace_minus = 0.; + tensorPlus_(A, [&](Real eig) { + trace_plus += std::max(eig, 0.); + trace_minus += std::min(eig, 0.); + }); - return std::make_pair(trace_plus, trace_minus); -} + return std::make_pair(trace_plus, trace_minus); + } -template -auto tensorPlusOp(const Eigen::MatrixBase &A, - Eigen::MatrixBase &A_directions, Op &&oper) { - Vector A_eigs; - Matrix A_diag; - A.eig(A_eigs, A_directions); + template + auto tensorPlusOp(const Eigen::MatrixBase & A, + Eigen::MatrixBase & A_directions, Op && oper) { + Vector A_eigs; + Matrix A_diag; + A.eig(A_eigs, A_directions); - for (auto &&data : enumerate(A_eigs)) { - auto i = std::get<0>(data); - A_diag(i, i) = oper(std::max(std::get<1>(data), 0.), i); - } + for (auto && data : enumerate(A_eigs)) { + auto i = std::get<0>(data); + A_diag(i, i) = oper(std::max(std::get<1>(data), 0.), i); + } - return A_directions * A_diag * A_directions.transpose(); -} + return A_directions * A_diag * A_directions.transpose(); + } -template -auto tensorPlus(const Eigen::MatrixBase &A, - Eigen::MatrixBase &A_directions) { - return tensorPlusOp(A, A_directions, [](Real x, Real) { return x; }); -} + template + auto tensorPlus(const Eigen::MatrixBase & A, + Eigen::MatrixBase & A_directions) { + return tensorPlusOp(A, A_directions, [](Real x, Real) { return x; }); + } -template -auto tensorPlusOp(const Eigen::MatrixBase &A, Op &&oper) { - Matrix A_directions; - return tensorPlusOp(A, A_directions, std::forward(oper)); -} + template + auto tensorPlusOp(const Eigen::MatrixBase & A, Op && oper) { + Matrix A_directions; + return tensorPlusOp(A, A_directions, std::forward(oper)); + } -template auto tensorPlus(const Eigen::MatrixBase &A) { - return tensorPlusOp(A, [](Real x, Real) { return x; }); -} + template auto tensorPlus(const Eigen::MatrixBase & A) { + return tensorPlusOp(A, [](Real x, Real) { return x; }); + } -template auto tensorSqrt(const Eigen::MatrixBase &A) { - return tensorPlusOp(A, [](Real x, Int) { return std::sqrt(x); }); -} + template auto tensorSqrt(const Eigen::MatrixBase & A) { + return tensorPlusOp(A, [](Real x, Int) { return std::sqrt(x); }); + } } // namespace /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template class EquivalentStrain, template class DamageThreshold, template class Parent> MaterialAnisotropicDamage:: - MaterialAnisotropicDamage(SolidMechanicsModel &model, const ID &id) + MaterialAnisotropicDamage(SolidMechanicsModel & model, const ID & id) : Parent(model, id), damage("damage_tensor", *this), elastic_stress("elastic_stress", *this), equivalent_strain("equivalent_strain", *this), trace_damage("trace_damage", *this), equivalent_strain_function(*this), damage_threshold_function(*this) { this->registerParam("Dc", Dc, _pat_parsable, "Critical damage"); this->damage.initialize(dim * dim); this->elastic_stress.initialize(dim * dim); this->equivalent_strain.initialize(1); this->trace_damage.initialize(1); this->trace_damage.initializeHistory(); } /* -------------------------------------------------------------------------- */ template class EquivalentStrain, template class DamageThreshold, template class Parent> template void MaterialAnisotropicDamage:: - damageStress(Eigen::MatrixBase &sigma, - const Eigen::MatrixBase &sigma_el, - const Eigen::MatrixBase &D, Real TrD) { + damageStress(Eigen::MatrixBase & sigma, + const Eigen::MatrixBase & sigma_el, + const Eigen::MatrixBase & D, Real TrD) { // σ_(n + 1) = (1 − D_(n + 1))^(1/2) σ~_(n + 1) (1 − D_(n + 1))^(1 / 2) // - ((1 − D_(n + 1)) : σ~_(n + 1))/ (3 - Tr(D_(n+1))) (1 − D_(n + 1)) // + 1/3 (1 - Tr(D_(n+1)) _+ + _-) I Matrix one_D = Matrix::Identity() - D; auto sqrt_one_D = tensorSqrt(one_D); Real Tr_sigma_plus; Real Tr_sigma_minus; std::tie(Tr_sigma_plus, Tr_sigma_minus) = tensorPlusTrace(sigma_el); auto I = Matrix::Identity(); sigma = sqrt_one_D * sigma_el * sqrt_one_D - (one_D.doubleDot(sigma_el) / (dim - TrD) * one_D) + 1. / dim * ((1 - TrD) * Tr_sigma_plus - Tr_sigma_minus) * I; } /* -------------------------------------------------------------------------- */ template class EquivalentStrain, template class DamageThreshold, template class Parent> template void MaterialAnisotropicDamage::computeStressOnQuad(Args &&args) { - auto &sigma = tuple::get<"sigma"_h>(args); - auto &grad_u = tuple::get<"grad_u"_h>(args); - auto &sigma_el = tuple::get<"sigma_el"_h>(args); - auto &epsilon_hat = tuple::get<"epsilon_hat"_h>(args); - auto &D = tuple::get<"damage"_h>(args); - auto &TrD_n_1 = tuple::get<"TrD_n_1"_h>(args); - auto &TrD = tuple::get<"TrD"_h>(args); - auto &equivalent_strain_data = tuple::get<"equivalent_strain_data"_h>(args); - auto &damage_threshold_data = tuple::get<"damage_threshold_data"_h>(args); + Parent>::computeStressOnQuad(Args && args) { + auto & sigma = tuple::get<"sigma"_h>(args); + auto & grad_u = tuple::get<"grad_u"_h>(args); + auto & sigma_el = tuple::get<"sigma_el"_h>(args); + auto & epsilon_hat = tuple::get<"epsilon_hat"_h>(args); + auto & D = tuple::get<"damage"_h>(args); + auto & TrD_n_1 = tuple::get<"TrD_n_1"_h>(args); + auto & TrD = tuple::get<"TrD"_h>(args); + auto & equivalent_strain_data = tuple::get<"equivalent_strain_data"_h>(args); + auto & damage_threshold_data = tuple::get<"damage_threshold_data"_h>(args); Matrix Dtmp; Real TrD_n_1_tmp; Matrix epsilon; // yes you read properly this is a label for a goto auto computeDamage = [&]() { MaterialElastic::computeStressOnQuad(args); epsilon = this->template gradUToEpsilon(grad_u); // evaluate the damage criteria epsilon_hat = equivalent_strain_function(epsilon, equivalent_strain_data); // evolve the damage if needed auto K_TrD = damage_threshold_function.K(TrD, damage_threshold_data); auto f = epsilon_hat - K_TrD; // if test function > 0 evolve the damage if (f > 0) { TrD_n_1_tmp = damage_threshold_function.K_inv(epsilon_hat, damage_threshold_data); auto epsilon_plus = tensorPlus(epsilon); auto delta_lambda = (TrD_n_1_tmp - TrD) / (epsilon_hat * epsilon_hat); Dtmp = D + delta_lambda * epsilon_plus; return true; } return false; }; // compute a temporary version of the new damage auto is_damage_updated = computeDamage(); if (is_damage_updated) { /// Check and correct for broken case if (Dtmp.trace() > Dc) { if (epsilon.trace() > 0) { // tensile loading auto kpa = this->kpa; auto lambda = this->lambda; // change kappa to Kappa_broken = (1-Dc) Kappa kpa = (1 - Dc) * kpa; this->E = 9 * kpa * (kpa - lambda) / (3 * kpa - lambda); this->nu = lambda / (3 * kpa - lambda); this->updateInternalParameters(); computeDamage(); } else if (std::abs(epsilon.trace()) < 1e-10) { // deviatoric case Matrix n; std::vector ns; tensorPlusOp(Dtmp, n, [&](Real x, Int i) { if (x > this->Dc) { ns.push_back(i); return this->Dc; } return x; }); } } TrD_n_1 = TrD_n_1_tmp; D = Dtmp; } else { TrD_n_1 = TrD; } // apply the damage to the stress damageStress(sigma, sigma_el, D, TrD_n_1); } /* -------------------------------------------------------------------------- */ template class EquivalentStrain, template class DamageThreshold, template class Parent> void MaterialAnisotropicDamage::computeStress(ElementType type, GhostType ghost_type) { - for (auto &&args : getArguments(type, ghost_type)) { + for (auto && args : getArguments(type, ghost_type)) { computeStressOnQuad(args); } } /* -------------------------------------------------------------------------- */ /* EquivalentStrain functions */ /* -------------------------------------------------------------------------- */ template class EquivalentStrainMazars : public EmptyIteratorContainer { public: EquivalentStrainMazars(Material & /*mat*/) {} template - Real operator()(const Eigen::MatrixBase &epsilon, Other &&.../*other*/) { + Real operator()(const Eigen::MatrixBase & epsilon, Other &&... /*other*/) { Real epsilon_hat = 0.; std::tie(epsilon_hat, std::ignore) = tensorPlusTrace(epsilon); return std::sqrt(epsilon_hat); } }; template class EquivalentStrainMazarsDruckerPrager : public EquivalentStrainMazars { public: - EquivalentStrainMazarsDruckerPrager(Material &mat) + EquivalentStrainMazarsDruckerPrager(Material & mat) : EquivalentStrainMazars(mat) { mat.registerParam("k", k, _pat_parsable, "k"); } template - Real operator()(const Eigen::MatrixBase &epsilon, Real) { + Real operator()(const Eigen::MatrixBase & epsilon, Real) { Real epsilon_hat = EquivalentStrainMazars::operator()(epsilon); epsilon_hat += k * epsilon.trace(); return epsilon_hat; } protected: Real k; }; /* -------------------------------------------------------------------------- */ /* DamageThreshold functions */ /* -------------------------------------------------------------------------- */ template class DamageThresholdLinear : public EmptyIteratorContainer { public: - DamageThresholdLinear(Material &mat) : mat(mat) { + DamageThresholdLinear(Material & mat) : mat(mat) { mat.registerParam("A", A, _pat_parsable, "A"); mat.registerParam("K0", K0, _pat_parsable, "K0"); } - template Real K(Real x, Other &&.../*other*/) { + template Real K(Real x, Other &&... /*other*/) { return 1. / A * x + K0; } - template Real K_inv(Real x, Other &&.../*other*/) { + template Real K_inv(Real x, Other &&... /*other*/) { return A * (x - K0); } private: - Material &mat; + Material & mat; Real A; Real K0; }; template class DamageThresholdTan : public EmptyIteratorContainer { public: - DamageThresholdTan(Material &mat) : mat(mat) { + DamageThresholdTan(Material & mat) : mat(mat) { mat.registerParam("a", a, _pat_parsable, "a"); mat.registerParam("A", A, _pat_parsable, "A"); mat.registerParam("K0", K0, _pat_parsable, "K0"); } - template Real K(Real x, Other &&.../*other*/) { + template Real K(Real x, Other &&... /*other*/) { return a * std::tan(std::atan2(x, a) - std::atan2(K0, a)); } - template Real K_inv(Real x, Other &&.../*other*/) { + template Real K_inv(Real x, Other &&... /*other*/) { return a * A * (std::atan2(x, a) - std::atan2(K0, a)); } private: - Material &mat; + Material & mat; Real a{2.93e-4}; Real A{5e3}; Real K0{5e-5}; }; } // namespace akantu #endif /* AKANTU_MATERIAL_ANISOTROPIC_DAMAGE_TMPL_HH_ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc index b70afd833..6b2ed20d8 100644 --- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc +++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc @@ -1,269 +1,267 @@ /** * @file material_elastic_linear_anisotropic.cc * * @author Aurelia Isabel Cuba Ramos * @author Till Junge * @author Enrico Milanese * @author Nicolas Richart * * @date creation: Wed Sep 25 2013 * @date last modification: Fri Jul 24 2020 * * @brief Anisotropic elastic material * * * @section LICENSE * * Copyright (©) 2014-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "material_elastic_linear_anisotropic.hh" #include "solid_mechanics_model.hh" #include #include namespace akantu { /* -------------------------------------------------------------------------- */ template MaterialElasticLinearAnisotropic::MaterialElasticLinearAnisotropic( SolidMechanicsModel & model, const ID & id, bool symmetric) : Material(model, id), rot_mat(dim, dim), Cprime(dim * dim, dim * dim), C(voigt_h::size, voigt_h::size), eigC(voigt_h::size), symmetric(symmetric), was_stiffness_assembled(false) { AKANTU_DEBUG_IN(); this->dir_vecs.push_back(std::make_unique>()); (*this->dir_vecs.back())[0] = 1.; this->registerParam("n1", *(this->dir_vecs.back()), _pat_parsmod, "Direction of main material axis"); if (dim > 1) { this->dir_vecs.push_back(std::make_unique>()); (*this->dir_vecs.back())[1] = 1.; this->registerParam("n2", *(this->dir_vecs.back()), _pat_parsmod, "Direction of secondary material axis"); } if (dim > 2) { this->dir_vecs.push_back(std::make_unique>()); (*this->dir_vecs.back())[2] = 1.; this->registerParam("n3", *(this->dir_vecs.back()), _pat_parsmod, "Direction of tertiary material axis"); } for (auto i : arange(voigt_h::size)) { decltype(i) start = 0; if (this->symmetric) { start = i; } for (auto j : arange(start, voigt_h::size)) { auto param = "C" + std::to_string(i + 1) + std::to_string(j + 1); this->registerParam(param, this->Cprime(i, j), Real(0.), _pat_parsmod, "Coefficient " + param); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialElasticLinearAnisotropic::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialElasticLinearAnisotropic::updateInternalParameters() { Material::updateInternalParameters(); if (this->symmetric) { for (auto i : arange(voigt_h::size)) { for (auto j : arange(i + 1, voigt_h::size)) { this->Cprime(j, i) = this->Cprime(i, j); } } } this->rotateCprime(); this->C.eig(this->eigC); this->was_stiffness_assembled = false; } /* -------------------------------------------------------------------------- */ template void MaterialElasticLinearAnisotropic::rotateCprime() { // start by filling the empty parts fo Cprime auto diff = Dim * Dim - voigt_h::size; for (auto i : arange(voigt_h::size, Dim * Dim)) { for (auto j : arange(Dim * Dim)) { this->Cprime(i, j) = this->Cprime(i - diff, j); } } for (auto i : arange(Dim * Dim)) { for (auto j : arange(voigt_h::size, Dim * Dim)) { this->Cprime(i, j) = this->Cprime(i, j - diff); } } // construction of rotator tensor // normalise rotation matrix for (auto j : arange(Dim)) { auto && rot_vec = this->rot_mat(j); rot_vec = *this->dir_vecs[j]; rot_vec.normalize(); } // make sure the vectors form a right-handed base - Vector v1, v2, v3; - v3.zero(); - + Vector test_axis = Vector::Zero(); if (Dim == 2) { - for (auto i : arange(Dim)) { - v1[i] = this->rot_mat(0, i); - v2[i] = this->rot_mat(1, i); - } + Vector v1 = Vector::Zero(); + Vector v2 = Vector::Zero(); + v1.block(0, 0) = this->rot_mat(0); + v2.block(0, 0) = this->rot_mat(1); - v3 = v1.cross(v2); + Vector v3 = v1.cross(v2); if (v3.norm() < 8 * std::numeric_limits::epsilon()) { AKANTU_ERROR("The axis vectors parallel."); } v3.normalize(); + test_axis = v1.cross(v2) - v3; } else if (Dim == 3) { - v1 = this->rot_mat(0); - v2 = this->rot_mat(1); - v3 = this->rot_mat(2); + Vector v1 = this->rot_mat(0); + Vector v2 = this->rot_mat(1); + Vector v3 = this->rot_mat(2); + test_axis = v1.cross(v2) - v3; } - Vector test_axis = v1.cross(v2) - v3; - if (test_axis.norm() > 8 * std::numeric_limits::epsilon()) { AKANTU_ERROR("The axis vectors do not form a right-handed coordinate " << "system. I. e., ||n1 x n2 - n3|| should be zero, but " << "it is " << test_axis.norm() << "."); } // create the rotator and the reverse rotator Matrix rotator; Matrix revrotor; for (auto i : arange(Dim)) { for (auto j : arange(Dim)) { for (auto k : arange(Dim)) { for (auto l : arange(Dim)) { auto I = voigt_h::mat[i][j]; auto J = voigt_h::mat[k][l]; rotator(I, J) = this->rot_mat(k, i) * this->rot_mat(l, j); revrotor(I, J) = this->rot_mat(i, k) * this->rot_mat(j, l); } } } } // create the full rotated matrix Matrix Cfull(Dim * Dim, Dim * Dim); Cfull = rotator * Cprime * revrotor; for (auto i : arange(voigt_h::size)) { for (auto j : arange(voigt_h::size)) { this->C(i, j) = Cfull(i, j); } } } /* -------------------------------------------------------------------------- */ template void MaterialElasticLinearAnisotropic::computeStress( ElementType el_type, GhostType ghost_type) { auto && arguments = getArguments(el_type, ghost_type); for (auto && data : arguments) { this->computeStressOnQuad(data); } } /* -------------------------------------------------------------------------- */ template void MaterialElasticLinearAnisotropic::computeTangentModuli( ElementType el_type, Array & tangent_matrix, GhostType ghost_type) { auto && arguments = Material::getArgumentsTangent(tangent_matrix, el_type, ghost_type); for (auto && args : arguments) { this->computeTangentModuliOnQuad(args); } this->was_stiffness_assembled = true; } /* -------------------------------------------------------------------------- */ template void MaterialElasticLinearAnisotropic::computePotentialEnergy( ElementType el_type) { AKANTU_DEBUG_ASSERT(!this->finite_deformation, "finite deformation not possible in material anisotropic " "(TO BE IMPLEMENTED)"); auto && arguments = Material::getArguments(el_type, _not_ghost); for (auto && args : zip(arguments, this->potential_energy(el_type, _not_ghost))) { this->computePotentialEnergyOnQuad(std::get<0>(args), std::get<1>(args)); } } /* -------------------------------------------------------------------------- */ template void MaterialElasticLinearAnisotropic::computePotentialEnergyByElement( ElementType type, Int index, Vector & epot_on_quad_points) { auto gradu_view = make_view(this->gradu(type)); auto stress_view = make_view(this->stress(type)); auto nb_quadrature_points = this->fem.getNbIntegrationPoints(type); auto gradu_it = gradu_view.begin() + index * nb_quadrature_points; auto gradu_end = gradu_it + nb_quadrature_points; auto stress_it = stress_view.begin() + index * nb_quadrature_points; auto stress_end = stress_it + nb_quadrature_points; auto epot_quad = epot_on_quad_points.begin(); Matrix grad_u(dim, dim); for (auto data : zip(tuple::get<"grad_u"_h>() = range(gradu_it, gradu_end), tuple::get<"sigma"_h>() = range(stress_it, stress_end), tuple::get<"Epot"_h>() = epot_on_quad_points)) { this->computePotentialEnergyOnQuad(data, tuple::get<"Epot"_h>(data)); } } /* -------------------------------------------------------------------------- */ template Real MaterialElasticLinearAnisotropic::getCelerity( const Element & /*element*/) const { return std::sqrt(this->eigC(0) / rho); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(elastic_anisotropic, MaterialElasticLinearAnisotropic); } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index 879bcca2c..dabdc39ef 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,599 +1,596 @@ /** * @file solid_mechanics_model.hh * * @author Guillaume Anciaux * @author Daniel Pino Muñoz * @author Nicolas Richart * * @date creation: Tue Jul 27 2010 * @date last modification: Fri Apr 09 2021 * * @brief Model of Solid Mechanics * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "data_accessor.hh" #include "fe_engine.hh" #include "model.hh" #include "non_local_manager_callback.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef AKANTU_SOLID_MECHANICS_MODEL_HH_ #define AKANTU_SOLID_MECHANICS_MODEL_HH_ namespace akantu { class Material; class MaterialSelector; class DumperIOHelper; class NonLocalManager; template class IntegratorGauss; template class ShapeLagrange; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ class SolidMechanicsModel : public Model, public DataAccessor, public DataAccessor, public BoundaryCondition, public NonLocalManagerCallback, public EventHandlerManager { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewMaterialElementsEvent : public NewElementsEvent { public: AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array &); AKANTU_GET_MACRO(MaterialList, material, const Array &); protected: Array material; }; using MyFEEngineType = FEEngineTemplate; protected: using EventManager = EventHandlerManager; public: - SolidMechanicsModel(Mesh & mesh, Int dim = _all_dimensions, - const ID & id = "solid_mechanics_model", + SolidMechanicsModel(Mesh &mesh, Int dim = _all_dimensions, + const ID &id = "solid_mechanics_model", std::shared_ptr dof_manager = nullptr, ModelType model_type = ModelType::_solid_mechanics_model); ~SolidMechanicsModel() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize completely the model void initFullImpl( - const ModelOptions & options = SolidMechanicsModelOptions()) override; + const ModelOptions &options = SolidMechanicsModelOptions()) override; public: /// initialize all internal arrays for materials virtual void initMaterials(); protected: /// initialize the model void initModel() override; /// function to print the containt of the class - void printself(std::ostream & stream, int indent = 0) const override; + void printself(std::ostream &stream, int indent = 0) const override; /// get some default values for derived classes std::tuple - getDefaultSolverID(const AnalysisMethod & method) override; + getDefaultSolverID(const AnalysisMethod &method) override; /* ------------------------------------------------------------------------ */ /* Solver interface */ /* ------------------------------------------------------------------------ */ public: /// assembles the stiffness matrix, virtual void assembleStiffnessMatrix(bool need_to_reassemble = false); /// assembles the internal forces in the array internal_forces virtual void assembleInternalForces(); protected: /// callback for the solver, this adds f_{ext} - f_{int} to the residual void assembleResidual() override; /// callback for the solver, this adds f_{ext} or f_{int} to the residual - void assembleResidual(const ID & residual_part) override; + void assembleResidual(const ID &residual_part) override; bool canSplitResidual() const override { return true; } /// get the type of matrix needed - MatrixType getMatrixType(const ID & matrix_id) const override; + MatrixType getMatrixType(const ID &matrix_id) const override; /// callback for the solver, this assembles different matrices - void assembleMatrix(const ID & matrix_id) override; + void assembleMatrix(const ID &matrix_id) override; /// callback for the solver, this assembles the stiffness matrix - void assembleLumpedMatrix(const ID & matrix_id) override; + void assembleLumpedMatrix(const ID &matrix_id) override; /// callback for the solver, this is called at beginning of solve void predictor() override; /// callback for the solver, this is called at end of solve void corrector() override; /// callback for the solver, this is called at beginning of solve void beforeSolveStep() override; /// callback for the solver, this is called at end of solve void afterSolveStep(bool converged = true) override; /// Callback for the model to instantiate the matricees when needed void initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType non_linear_solver_type) override; protected: /* ------------------------------------------------------------------------ */ TimeStepSolverType getDefaultSolverType() const override; /* ------------------------------------------------------------------------ */ ModelSolverOptions - getDefaultSolverOptions(const TimeStepSolverType & type) const override; + getDefaultSolverOptions(const TimeStepSolverType &type) const override; public: bool isDefaultSolverExplicit() { return method == _explicit_lumped_mass || method == _explicit_consistent_mass; } protected: /// update the current position vector void updateCurrentPosition(); /* ------------------------------------------------------------------------ */ /* Materials (solid_mechanics_model_material.cc) */ /* ------------------------------------------------------------------------ */ public: /// register an empty material of a given type - Material & registerNewMaterial(const ID & mat_name, const ID & mat_type, - const ID & opt_param); + Material ®isterNewMaterial(const ID &mat_name, const ID &mat_type, + const ID &opt_param); /// reassigns materials depending on the material selector virtual void reassignMaterial(); /// apply a constant eigen_grad_u on all quadrature points of a given material - virtual void applyEigenGradU(const Matrix & prescribed_eigen_grad_u, - const ID & material_name, + virtual void applyEigenGradU(const Matrix &prescribed_eigen_grad_u, + const ID &material_name, GhostType ghost_type = _not_ghost); protected: /// register a material in the dynamic database - Material & registerNewMaterial(const ParserSection & mat_section); + Material ®isterNewMaterial(const ParserSection &mat_section); /// read the material files to instantiate all the materials void instantiateMaterials(); /// set the element_id_by_material and add the elements to the good materials virtual void - assignMaterialToElements(const ElementTypeMapArray * filter = nullptr); + assignMaterialToElements(const ElementTypeMapArray *filter = nullptr); /* ------------------------------------------------------------------------ */ /* Mass (solid_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); public: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); protected: /// fill a vector of rho - void computeRho(Array & rho, ElementType type, GhostType ghost_type); + void computeRho(Array &rho, ElementType type, GhostType ghost_type); /// compute the kinetic energy Real getKineticEnergy(); [[gnu::deprecated("Use the interface with an Element")]] Real getKineticEnergy(ElementType type, Idx index) { return getKineticEnergy({type, index, _not_ghost}); } - Real getKineticEnergy(const Element & element); + Real getKineticEnergy(const Element &element); /// compute the external work (for impose displacement, the velocity should be /// given too) Real getExternalWork(); /* ------------------------------------------------------------------------ */ /* NonLocalManager inherited members */ /* ------------------------------------------------------------------------ */ protected: void initializeNonLocal() override; - void updateDataForNonLocalCriterion(ElementTypeMapReal & criterion) override; + void updateDataForNonLocalCriterion(ElementTypeMapReal &criterion) override; void computeNonLocalStresses(GhostType ghost_type) override; void insertIntegrationPointsInNeighborhoods(GhostType ghost_type) override; /// update the values of the non local internal - void updateLocalInternal(ElementTypeMapReal & internal_flat, + void updateLocalInternal(ElementTypeMapReal &internal_flat, GhostType ghost_type, ElementKind kind) override; /// copy the results of the averaging in the materials - void updateNonLocalInternal(ElementTypeMapReal & internal_flat, + void updateNonLocalInternal(ElementTypeMapReal &internal_flat, GhostType ghost_type, ElementKind kind) override; /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: - Int getNbData(const Array & elements, - const SynchronizationTag & tag) const override; + Int getNbData(const Array &elements, + const SynchronizationTag &tag) const override; - void packData(CommunicationBuffer & buffer, const Array & elements, - const SynchronizationTag & tag) const override; + void packData(CommunicationBuffer &buffer, const Array &elements, + const SynchronizationTag &tag) const override; - void unpackData(CommunicationBuffer & buffer, const Array & elements, - const SynchronizationTag & tag) override; + void unpackData(CommunicationBuffer &buffer, const Array &elements, + const SynchronizationTag &tag) override; - Int getNbData(const Array & dofs, - const SynchronizationTag & tag) const override; + Int getNbData(const Array &dofs, + const SynchronizationTag &tag) const override; - void packData(CommunicationBuffer & buffer, const Array & dofs, - const SynchronizationTag & tag) const override; + void packData(CommunicationBuffer &buffer, const Array &dofs, + const SynchronizationTag &tag) const override; - void unpackData(CommunicationBuffer & buffer, const Array & dofs, - const SynchronizationTag & tag) override; + void unpackData(CommunicationBuffer &buffer, const Array &dofs, + const SynchronizationTag &tag) override; protected: void - splitElementByMaterial(const Array & elements, - std::vector> & elements_per_mat) const; + splitElementByMaterial(const Array &elements, + std::vector> &elements_per_mat) const; template - void splitByMaterial(const Array & elements, Operation && op) const; + void splitByMaterial(const Array &elements, Operation &&op) const; /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: - void onNodesAdded(const Array & nodes_list, - const NewNodesEvent & event) override; - void onNodesRemoved(const Array & element_list, - const Array & new_numbering, - const RemovedNodesEvent & event) override; - void onElementsAdded(const Array & element_list, - const NewElementsEvent & event) override; - void onElementsRemoved(const Array & element_list, - const ElementTypeMapArray & new_numbering, - const RemovedElementsEvent & event) override; + void onNodesAdded(const Array &nodes_list, + const NewNodesEvent &event) override; + void onNodesRemoved(const Array &element_list, + const Array &new_numbering, + const RemovedNodesEvent &event) override; + void onElementsAdded(const Array &element_list, + const NewElementsEvent &event) override; + void onElementsRemoved(const Array &element_list, + const ElementTypeMapArray &new_numbering, + const RemovedElementsEvent &event) override; void onElementsChanged(const Array &, const Array &, const ElementTypeMapArray &, const ChangedElementsEvent &) override{}; /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ public: virtual void onDump(); //! decide wether a field is a material internal or not - bool isInternal(const std::string & field_name, ElementKind element_kind); + bool isInternal(const std::string &field_name, ElementKind element_kind); //! give the amount of data per element virtual ElementTypeMap - getInternalDataPerElem(const std::string & field_name, - ElementKind kind); + getInternalDataPerElem(const std::string &field_name, ElementKind kind); //! flatten a given material internal field - ElementTypeMapArray & - flattenInternal(const std::string & field_name, ElementKind kind, - GhostType ghost_type = _not_ghost); + ElementTypeMapArray &flattenInternal(const std::string &field_name, + ElementKind kind, + GhostType ghost_type = _not_ghost); //! flatten all the registered material internals void flattenAllRegisteredInternals(ElementKind kind); std::shared_ptr - createNodalFieldReal(const std::string & field_name, - const std::string & group_name, + createNodalFieldReal(const std::string &field_name, + const std::string &group_name, bool padding_flag) override; std::shared_ptr - createNodalFieldBool(const std::string & field_name, - const std::string & group_name, + createNodalFieldBool(const std::string &field_name, + const std::string &group_name, bool padding_flag) override; std::shared_ptr - createElementalField(const std::string & field_name, - const std::string & group_name, bool padding_flag, - Int spatial_dimension, - ElementKind kind) override; + createElementalField(const std::string &field_name, + const std::string &group_name, bool padding_flag, + Int spatial_dimension, ElementKind kind) override; - void dump(const std::string & dumper_name) override; - void dump(const std::string & dumper_name, Int step) override; - void dump(const std::string & dumper_name, Real time, Int step) override; + void dump(const std::string &dumper_name) override; + void dump(const std::string &dumper_name, Int step) override; + void dump(const std::string &dumper_name, Real time, Int step) override; void dump() override; void dump(Int step) override; void dump(Real time, Int step) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// set the value of the time step - void setTimeStep(Real time_step, const ID & solver_id = "") override; + void setTimeStep(Real time_step, const ID &solver_id = "") override; /// get the value of the conversion from forces/ mass to acceleration AKANTU_GET_MACRO(F_M2A, f_m2a, Real); /// set the value of the conversion from forces/ mass to acceleration AKANTU_SET_MACRO(F_M2A, f_m2a, Real); /// get the SolidMechanicsModel::displacement array AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(Displacement, displacement); /// get the SolidMechanicsModel::displacement array AKANTU_GET_MACRO_DEREF_PTR(Displacement, displacement); /// get the SolidMechanicsModel::previous_displacement array AKANTU_GET_MACRO_DEREF_PTR(PreviousDisplacement, previous_displacement); /// get the SolidMechanicsModel::current_position array - const Array & getCurrentPosition(); + const Array &getCurrentPosition(); /// get the SolidMechanicsModel::displacement_increment array AKANTU_GET_MACRO_DEREF_PTR(Increment, displacement_increment); /// get the SolidMechanicsModel::displacement_increment array AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(Increment, displacement_increment); /// get the lumped SolidMechanicsModel::mass array AKANTU_GET_MACRO_DEREF_PTR(Mass, mass); /// get the SolidMechanicsModel::velocity array AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(Velocity, velocity); /// get the SolidMechanicsModel::velocity array AKANTU_GET_MACRO_DEREF_PTR(Velocity, velocity); /// get the SolidMechanicsModel::acceleration array AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(Acceleration, acceleration); /// get the SolidMechanicsModel::acceleration array AKANTU_GET_MACRO_DEREF_PTR(Acceleration, acceleration); /// get the SolidMechanicsModel::external_force array AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(ExternalForce, external_force); /// get the SolidMechanicsModel::external_force array AKANTU_GET_MACRO_DEREF_PTR(ExternalForce, external_force); /// get the SolidMechanicsModel::force array (external forces) [[deprecated("Use getExternalForce instead of this function")]] Array & getForce() { return getExternalForce(); } /// get the SolidMechanicsModel::internal_force array (internal forces) AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(InternalForce, internal_force); /// get the SolidMechanicsModel::internal_force array (internal forces) AKANTU_GET_MACRO_DEREF_PTR(InternalForce, internal_force); /// get the SolidMechanicsModel::blocked_dofs array AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(BlockedDOFs, blocked_dofs); /// get the SolidMechanicsModel::blocked_dofs array AKANTU_GET_MACRO_DEREF_PTR(BlockedDOFs, blocked_dofs); /// get an iterable on the materials inline decltype(auto) getMaterials(); /// get an iterable on the materials inline decltype(auto) getMaterials() const; /// get a particular material (by numerical material index) - inline Material & getMaterial(UInt mat_index); + inline Material &getMaterial(UInt mat_index); /// get a particular material (by numerical material index) - inline const Material & getMaterial(UInt mat_index) const; + inline const Material &getMaterial(UInt mat_index) const; /// get a particular material (by material name) - inline Material & getMaterial(const std::string & name); + inline Material &getMaterial(const std::string &name); /// get a particular material (by material name) - inline const Material & getMaterial(const std::string & name) const; + inline const Material &getMaterial(const std::string &name) const; /// get a particular material id from is name - inline Int getMaterialIndex(const std::string & name) const; + inline Int getMaterialIndex(const std::string &name) const; /// give the number of materials - inline UInt getNbMaterials() const { return materials.size(); } + inline Int getNbMaterials() const { return materials.size(); } /// give the material internal index from its id - Int getInternalIndexFromID(const ID & id) const; + Int getInternalIndexFromID(const ID &id) const; /// compute the stable time step Real getStableTimeStep(); /** * @brief Returns the total energy for a given energy type * * Energy types of SolidMechanicsModel expected as argument are: * - `kinetic` * - `external work` * * Other energy types are passed on to the materials. All materials should * define a `potential` energy type. For additional energy types, see material * documentation. */ - Real getEnergy(const std::string & energy_id); + Real getEnergy(const std::string &energy_id); /// compute the energy for one element - Real getEnergy(const std::string & energy_id, const Element & element); + Real getEnergy(const std::string &energy_id, const Element &element); [[gnu::deprecated("Use the interface with an Element")]] Real - getEnergy(const std::string & energy_id, ElementType type, - Int index) { + getEnergy(const std::string &energy_id, ElementType type, Int index) { return getEnergy(energy_id, Element{type, index, _not_ghost}); } /// Compute energy for an element group - Real getEnergy(const ID & energy_id, const ID & group_id); + Real getEnergy(const ID &energy_id, const ID &group_id); AKANTU_GET_MACRO_AUTO(MaterialByElement, material_index); AKANTU_GET_MACRO_AUTO(MaterialLocalNumbering, material_local_numbering); /// vectors containing local material element index for each global element /// index AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialByElement, material_index, Int); // AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialByElement, material_index, Int); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialLocalNumbering, material_local_numbering, Int); // AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialLocalNumbering, // material_local_numbering, UInt); AKANTU_GET_MACRO_NOT_CONST(MaterialSelector, material_selector, std::shared_ptr); void setMaterialSelector(std::shared_ptr material_selector) { this->material_selector = std::move(material_selector); } /// Access the non_local_manager interface AKANTU_GET_MACRO(NonLocalManager, *non_local_manager, NonLocalManager &); /// get the FEEngine object to integrate or interpolate on the boundary - FEEngine & getFEEngineBoundary(const ID & name = "") override; + FEEngine &getFEEngineBoundary(const ID &name = "") override; protected: /// compute the stable time step Real getStableTimeStep(GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// release version of the displacement array Int displacement_release{0}; /// release version of the current_position array Int current_position_release{0}; /// Check if materials need to recompute the mass array bool need_to_reassemble_lumped_mass{true}; /// Check if materials need to recompute the mass matrix bool need_to_reassemble_mass{true}; /// mapping between material name and material internal id std::map materials_names_to_id; protected: /// conversion coefficient form force/mass to acceleration Real f_m2a{1.0}; /// displacements array std::unique_ptr> displacement; /// displacements array at the previous time step (used in finite deformation) std::unique_ptr> previous_displacement; /// increment of displacement std::unique_ptr> displacement_increment; /// lumped mass array std::unique_ptr> mass; /// velocities array std::unique_ptr> velocity; /// accelerations array std::unique_ptr> acceleration; /// external forces array std::unique_ptr> external_force; /// internal forces array std::unique_ptr> internal_force; /// array specifing if a degree of freedom is blocked or not std::unique_ptr> blocked_dofs; /// array of current position used during update residual std::unique_ptr> current_position; /// Arrays containing the material index for each element ElementTypeMapArray material_index; /// Arrays containing the position in the element filter of the material /// (material's local numbering) ElementTypeMapArray material_local_numbering; /// list of used materials std::vector> materials; /// class defining of to choose a material std::shared_ptr material_selector; using flatten_internal_map = std::map, std::unique_ptr>>; /// tells if the material are instantiated flatten_internal_map registered_internals; /// non local manager std::unique_ptr non_local_manager; /// tells if the material are instantiated bool are_materials_instantiated{false}; friend class Material; template friend class CouplerSolidContactTemplate; }; /* -------------------------------------------------------------------------- */ namespace BC { - namespace Neumann { - using FromStress = FromHigherDim; - using FromTraction = FromSameDim; - } // namespace Neumann +namespace Neumann { +using FromStress = FromHigherDim; +using FromTraction = FromSameDim; +} // namespace Neumann } // namespace BC } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "parser.hh" #include "solid_mechanics_model_inline_impl.hh" #include "solid_mechanics_model_tmpl.hh" /* -------------------------------------------------------------------------- */ #endif /* AKANTU_SOLID_MECHANICS_MODEL_HH_ */ diff --git a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh index 4ebe16de0..ff2250f70 100644 --- a/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh +++ b/src/model/structural_mechanics/structural_elements/structural_element_bernoulli_beam_3.hh @@ -1,76 +1,76 @@ /** * @file structural_element_bernoulli_beam_3.hh * * @author Fabian Barras * @author Lucas Frerot * @author Sébastien Hartmann * @author Nicolas Richart * @author Damien Spielmann * * @date creation: Wed Oct 11 2017 * @date last modification: Fri Feb 05 2021 * * @brief Specific functions for bernoulli beam 3d * * * @section LICENSE * * Copyright (©) 2016-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH_ #define AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH_ #include "structural_mechanics_model.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_3>( - Array & tangent_moduli) { - UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); - UInt nb_quadrature_points = + Array &tangent_moduli) { + Int nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); + Int nb_quadrature_points = getFEEngine().getNbIntegrationPoints(_bernoulli_beam_3); - UInt tangent_size = 4; + Int tangent_size = 4; tangent_moduli.zero(); Array::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); for (Int e = 0; e < nb_element; ++e) { UInt mat = element_material(_bernoulli_beam_3, _not_ghost)(e); Real E = materials[mat].E; Real A = materials[mat].A; Real Iz = materials[mat].Iz; Real Iy = materials[mat].Iy; Real GJ = materials[mat].GJ; for (Int q = 0; q < nb_quadrature_points; ++q, ++D_it) { - auto & D = *D_it; + auto &D = *D_it; D(0, 0) = E * A; D(1, 1) = E * Iz; D(2, 2) = E * Iy; D(3, 3) = GJ; } } } } // namespace akantu #endif /* AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_BEAM_3_HH_ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc index 1110f9910..273142544 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.cc +++ b/src/model/structural_mechanics/structural_mechanics_model.cc @@ -1,621 +1,621 @@ /** * @file structural_mechanics_model.cc * * @author Fabian Barras * @author Lucas Frerot * @author Sébastien Hartmann * @author Nicolas Richart * @author Damien Spielmann * * @date creation: Fri Jul 15 2011 * @date last modification: Mon Mar 15 2021 * * @brief Model implementation for Structural Mechanics elements * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model.hh" #include "dof_manager.hh" #include "integrator_gauss.hh" #include "mesh.hh" #include "shape_structural.hh" #include "sparse_matrix.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #include "dumpable_inline_impl.hh" #include "dumper_elemental_field.hh" #include "dumper_internal_material_field.hh" #include "dumper_iohelper_paraview.hh" #include "group_manager_inline_impl.hh" /* -------------------------------------------------------------------------- */ #include "structural_element_bernoulli_beam_2.hh" #include "structural_element_bernoulli_beam_3.hh" #include "structural_element_kirchhoff_shell.hh" /* -------------------------------------------------------------------------- */ //#include "structural_mechanics_model_inline_impl.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt StructuralMechanicsModel::getNbDegreeOfFreedom(ElementType type) { return tuple_dispatch>( - [&](auto && enum_type) { + [&](auto &&enum_type) { constexpr ElementType type = std::decay_t::value; return ElementClass::getNbDegreeOfFreedom(); }, type); } /* -------------------------------------------------------------------------- */ -StructuralMechanicsModel::StructuralMechanicsModel(Mesh & mesh, Int dim, - const ID & id) +StructuralMechanicsModel::StructuralMechanicsModel(Mesh &mesh, Int dim, + const ID &id) : Model(mesh, ModelType::_structural_mechanics_model, dim, id), f_m2a(1.0), stress("stress", id), element_material("element_material", id), set_ID("beam sets", id) { AKANTU_DEBUG_IN(); registerFEEngineObject("StructuralMechanicsFEEngine", mesh, spatial_dimension); if (spatial_dimension == 2) { nb_degree_of_freedom = 3; } else if (spatial_dimension == 3) { nb_degree_of_freedom = 6; } else { AKANTU_TO_IMPLEMENT(); } this->mesh.registerDumper("structural_mechanics_model", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_structural); this->initDOFManager(); this->dumper_default_element_kind = _ek_structural; mesh.getElementalData("extra_normal") .initialize(mesh, _element_kind = _ek_structural, _nb_component = spatial_dimension, _with_nb_element = true, _default_value = 0.); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::~StructuralMechanicsModel() = default; /* -------------------------------------------------------------------------- */ -void StructuralMechanicsModel::initFullImpl(const ModelOptions & options) { +void StructuralMechanicsModel::initFullImpl(const ModelOptions &options) { Model::initFullImpl(options); // Initializing stresses ElementTypeMap stress_components; /// TODO this is ugly af, maybe add a function to FEEngine - for (auto && type : mesh.elementTypes(_spatial_dimension = _all_dimensions, - _element_kind = _ek_structural)) { + for (auto &&type : mesh.elementTypes(_spatial_dimension = _all_dimensions, + _element_kind = _ek_structural)) { UInt nb_components = 0; // Getting number of components for each element type #define GET_(type) nb_components = ElementClass::getNbStressComponents() AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(GET_); #undef GET_ stress_components(nb_components, type); } stress.initialize( getFEEngine(), _spatial_dimension = _all_dimensions, _element_kind = _ek_structural, _nb_component = [&stress_components](ElementType type, GhostType /*unused*/) -> UInt { return stress_components(type); }); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initFEEngineBoundary() { /// TODO: this function should not be reimplemented /// we're just avoiding a call to Model::initFEEngineBoundary() } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::setTimeStep(Real time_step, - const ID & solver_id) { + const ID &solver_id) { Model::setTimeStep(time_step, solver_id); this->mesh.getDumper().setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initSolver( TimeStepSolverType time_step_solver_type, NonLinearSolverType /*unused*/) { AKANTU_DEBUG_IN(); this->allocNodalField(displacement_rotation, nb_degree_of_freedom, "displacement"); this->allocNodalField(external_force, nb_degree_of_freedom, "external_force"); this->allocNodalField(internal_force, nb_degree_of_freedom, "internal_force"); this->allocNodalField(blocked_dofs, nb_degree_of_freedom, "blocked_dofs"); - auto & dof_manager = this->getDOFManager(); + auto &dof_manager = this->getDOFManager(); if (not dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *displacement_rotation, _dst_nodal); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); } if (time_step_solver_type == TimeStepSolverType::_dynamic || time_step_solver_type == TimeStepSolverType::_dynamic_lumped) { this->allocNodalField(velocity, nb_degree_of_freedom, "velocity"); this->allocNodalField(acceleration, nb_degree_of_freedom, "acceleration"); if (!dof_manager.hasDOFsDerivatives("displacement", 1)) { dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity); dof_manager.registerDOFsDerivative("displacement", 2, *this->acceleration); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initModel() { element_material.initialize(mesh, _element_kind = _ek_structural, _default_value = 0, _with_nb_element = true); getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); if (not need_to_reassemble_stiffness) { return; } if (not getDOFManager().hasMatrix("K")) { getDOFManager().getNewMatrix("K", getMatrixType("K")); } this->getDOFManager().zeroMatrix("K"); - for (const auto & type : + for (const auto &type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { #define ASSEMBLE_STIFFNESS_MATRIX(type) assembleStiffnessMatrix(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(ASSEMBLE_STIFFNESS_MATRIX); #undef ASSEMBLE_STIFFNESS_MATRIX } need_to_reassemble_stiffness = false; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeStresses() { AKANTU_DEBUG_IN(); - for (const auto & type : + for (const auto &type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { #define COMPUTE_STRESS_ON_QUAD(type) computeStressOnQuad(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_STRESS_ON_QUAD); #undef COMPUTE_STRESS_ON_QUAD } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ std::shared_ptr StructuralMechanicsModel::createNodalFieldBool( - const std::string & field_name, const std::string & group_name, + const std::string &field_name, const std::string &group_name, __attribute__((unused)) bool padding_flag) { std::map *> uint_nodal_fields; uint_nodal_fields["blocked_dofs"] = blocked_dofs.get(); return mesh.createNodalField(uint_nodal_fields[field_name], group_name); } /* -------------------------------------------------------------------------- */ std::shared_ptr -StructuralMechanicsModel::createNodalFieldReal(const std::string & field_name, - const std::string & group_name, +StructuralMechanicsModel::createNodalFieldReal(const std::string &field_name, + const std::string &group_name, bool padding_flag) { UInt n; if (spatial_dimension == 2) { n = 2; } else { n = 3; } UInt padding_size = 0; if (padding_flag) { padding_size = 3; } if (field_name == "displacement") { return mesh.createStridedNodalField(displacement_rotation.get(), group_name, n, 0, padding_size); } if (field_name == "velocity") { return mesh.createStridedNodalField(velocity.get(), group_name, n, 0, padding_size); } if (field_name == "acceleration") { return mesh.createStridedNodalField(acceleration.get(), group_name, n, 0, padding_size); } if (field_name == "rotation") { return mesh.createStridedNodalField(displacement_rotation.get(), group_name, nb_degree_of_freedom - n, n, padding_size); } if (field_name == "force") { return mesh.createStridedNodalField(external_force.get(), group_name, n, 0, padding_size); } if (field_name == "external_force") { return mesh.createStridedNodalField(external_force.get(), group_name, n, 0, padding_size); } if (field_name == "momentum") { return mesh.createStridedNodalField(external_force.get(), group_name, nb_degree_of_freedom - n, n, padding_size); } if (field_name == "internal_force") { return mesh.createStridedNodalField(internal_force.get(), group_name, n, 0, padding_size); } if (field_name == "internal_momentum") { return mesh.createStridedNodalField(internal_force.get(), group_name, nb_degree_of_freedom - n, n, padding_size); } return nullptr; } /* -------------------------------------------------------------------------- */ std::shared_ptr StructuralMechanicsModel::createElementalField( - const std::string & field_name, const std::string & group_name, + const std::string &field_name, const std::string &group_name, bool /*unused*/, Int spatial_dimension, ElementKind kind) { std::shared_ptr field; if (field_name == "element_index_by_material") { field = mesh.createElementalField, dumpers::ElementalField>( field_name, group_name, spatial_dimension, kind); } if (field_name == "stress") { ElementTypeMap nb_data_per_elem = this->mesh.getNbDataPerElem(stress); field = mesh.createElementalField( stress, group_name, this->spatial_dimension, kind, nb_data_per_elem); } return field; } /* -------------------------------------------------------------------------- */ /* Virtual methods from SolverCallback */ /* -------------------------------------------------------------------------- */ /// get the type of matrix needed MatrixType StructuralMechanicsModel::getMatrixType(const ID & /*id*/) const { return _symmetric; } /// callback to assemble a Matrix -void StructuralMechanicsModel::assembleMatrix(const ID & id) { +void StructuralMechanicsModel::assembleMatrix(const ID &id) { if (id == "K") { assembleStiffnessMatrix(); } else if (id == "M") { assembleMassMatrix(); } } /// callback to assemble a lumped Matrix void StructuralMechanicsModel::assembleLumpedMatrix(const ID & /*id*/) {} /// callback to assemble the residual StructuralMechanicsModel::(rhs) void StructuralMechanicsModel::assembleResidual() { AKANTU_DEBUG_IN(); - auto & dof_manager = getDOFManager(); + auto &dof_manager = getDOFManager(); assembleInternalForce(); dof_manager.assembleToResidual("displacement", *external_force, 1); dof_manager.assembleToResidual("displacement", *internal_force, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -void StructuralMechanicsModel::assembleResidual(const ID & residual_part) { +void StructuralMechanicsModel::assembleResidual(const ID &residual_part) { AKANTU_DEBUG_IN(); if ("external" == residual_part) { this->getDOFManager().assembleToResidual("displacement", *this->external_force, 1); AKANTU_DEBUG_OUT(); return; } if ("internal" == residual_part) { this->assembleInternalForce(); this->getDOFManager().assembleToResidual("displacement", *this->internal_force, 1); AKANTU_DEBUG_OUT(); return; } AKANTU_CUSTOM_EXCEPTION( debug::SolverCallbackResidualPartUnknown(residual_part)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Virtual methods from Model */ /* -------------------------------------------------------------------------- */ /// get some default values for derived classes std::tuple -StructuralMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) { +StructuralMechanicsModel::getDefaultSolverID(const AnalysisMethod &method) { switch (method) { case _static: { return std::make_tuple("static", TimeStepSolverType::_static); } case _implicit_dynamic: { return std::make_tuple("implicit", TimeStepSolverType::_dynamic); } default: return std::make_tuple("unknown", TimeStepSolverType::_not_defined); } } /* ------------------------------------------------------------------------ */ ModelSolverOptions StructuralMechanicsModel::getDefaultSolverOptions( - const TimeStepSolverType & type) const { + const TimeStepSolverType &type) const { ModelSolverOptions options; switch (type) { case TimeStepSolverType::_static: { options.non_linear_solver_type = NonLinearSolverType::_newton_raphson; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } case TimeStepSolverType::_dynamic: { options.non_linear_solver_type = NonLinearSolverType::_newton_raphson; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_trapezoidal_rule_2; options.solution_type["displacement"] = IntegrationScheme::_displacement; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleInternalForce() { internal_force->zero(); computeStresses(); for (auto type : mesh.elementTypes(_spatial_dimension = _all_dimensions, _element_kind = _ek_structural)) { assembleInternalForce(type, _not_ghost); // assembleInternalForce(type, _ghost); } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleInternalForce(ElementType type, GhostType gt) { - auto & fem = getFEEngine(); - auto & sigma = stress(type, gt); + auto &fem = getFEEngine(); + auto &sigma = stress(type, gt); auto ndof = getNbDegreeOfFreedom(type); auto nb_nodes = mesh.getNbNodesPerElement(type); auto ndof_per_elem = ndof * nb_nodes; Array BtSigma(fem.getNbIntegrationPoints(type) * mesh.getNbElement(type), ndof_per_elem, "BtSigma"); fem.computeBtD(sigma, BtSigma, type, gt); Array intBtSigma(0, ndof_per_elem, "intBtSigma"); fem.integrate(BtSigma, intBtSigma, ndof_per_elem, type, gt); getDOFManager().assembleElementalArrayLocalArray(intBtSigma, *internal_force, type, gt, -1.); } /* -------------------------------------------------------------------------- */ Real StructuralMechanicsModel::getKineticEnergy() { if (not this->getDOFManager().hasMatrix("M")) { return 0.; } Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); Array Mv(nb_nodes, nb_degree_of_freedom); this->getDOFManager().assembleMatMulVectToArray("displacement", "M", *this->velocity, Mv); - for (auto && data : zip(arange(nb_nodes), make_view(Mv, nb_degree_of_freedom), - make_view(*this->velocity, nb_degree_of_freedom))) { + for (auto &&data : zip(arange(nb_nodes), make_view(Mv, nb_degree_of_freedom), + make_view(*this->velocity, nb_degree_of_freedom))) { ekin += std::get<2>(data).dot(std::get<1>(data)) * static_cast(mesh.isLocalOrMasterNode(std::get<0>(data))); } mesh.getCommunicator().allReduce(ekin, SynchronizerOperation::_sum); return ekin / 2.; } /* -------------------------------------------------------------------------- */ Real StructuralMechanicsModel::getPotentialEnergy() { Real epot = 0.; UInt nb_nodes = mesh.getNbNodes(); Array Ku(nb_nodes, nb_degree_of_freedom); this->getDOFManager().assembleMatMulVectToArray( "displacement", "K", *this->displacement_rotation, Ku); - for (auto && data : + for (auto &&data : zip(arange(nb_nodes), make_view(Ku, nb_degree_of_freedom), make_view(*this->displacement_rotation, nb_degree_of_freedom))) { epot += std::get<2>(data).dot(std::get<1>(data)) * static_cast(mesh.isLocalOrMasterNode(std::get<0>(data))); } mesh.getCommunicator().allReduce(epot, SynchronizerOperation::_sum); return epot / 2.; } /* -------------------------------------------------------------------------- */ -Real StructuralMechanicsModel::getEnergy(const ID & energy) { +Real StructuralMechanicsModel::getEnergy(const ID &energy) { if (energy == "kinetic") { return getKineticEnergy(); } if (energy == "potential") { return getPotentialEnergy(); } return 0; } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeForcesByLocalTractionArray( - const Array & tractions, ElementType type) { + const Array &tractions, ElementType type) { AKANTU_DEBUG_IN(); auto nb_element = getFEEngine().getMesh().getNbElement(type); auto nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(type); auto nb_quad = getFEEngine().getNbIntegrationPoints(type); // check dimension match AKANTU_DEBUG_ASSERT( Mesh::getSpatialDimension(type) == getFEEngine().getElementDimension(), "element type dimension does not match the dimension of boundaries : " << getFEEngine().getElementDimension() << " != " << Mesh::getSpatialDimension(type)); // check size of the vector AKANTU_DEBUG_ASSERT( tractions.size() == nb_quad * nb_element, "the size of the vector should be the total number of quadrature points"); // check number of components AKANTU_DEBUG_ASSERT(tractions.getNbComponent() == nb_degree_of_freedom, "the number of components should be the spatial " "dimension of the problem"); Array Ntbs(nb_element * nb_quad, nb_degree_of_freedom * nb_nodes_per_element); - auto & fem = getFEEngine(); + auto &fem = getFEEngine(); fem.computeNtb(tractions, Ntbs, type); // allocate the vector that will contain the integrated values auto name = id + std::to_string(type) + ":integral_boundary"; Array int_funct(nb_element, nb_degree_of_freedom * nb_nodes_per_element, name); // do the integration getFEEngine().integrate(Ntbs, int_funct, nb_degree_of_freedom * nb_nodes_per_element, type); // assemble the result into force vector getDOFManager().assembleElementalArrayLocalArray(int_funct, *external_force, type, _not_ghost, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeForcesByGlobalTractionArray( - const Array & traction_global, ElementType type) { + const Array &traction_global, ElementType type) { AKANTU_DEBUG_IN(); - UInt nb_element = mesh.getNbElement(type); - UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); + auto nb_element = mesh.getNbElement(type); + auto nb_quad = getFEEngine().getNbIntegrationPoints(type); Array traction_local(nb_element * nb_quad, nb_degree_of_freedom, id + ":structuralmechanics:imposed_linear_load"); auto R_it = getFEEngineClass() .getShapeFunctions() .getRotations(type) .begin(nb_degree_of_freedom, nb_degree_of_freedom); auto Te_it = traction_global.begin(nb_degree_of_freedom); auto te_it = traction_local.begin(nb_degree_of_freedom); for (Int e = 0; e < nb_element; ++e, ++R_it) { for (Int q = 0; q < nb_quad; ++q, ++Te_it, ++te_it) { // turn the traction in the local referential *te_it = *R_it * *Te_it; } } computeForcesByLocalTractionArray(traction_local, type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::afterSolveStep(bool converged) { if (converged) { assembleInternalForce(); } } } // namespace akantu diff --git a/test/test_common/test_csr.cc b/test/test_common/test_csr.cc index 3df4b6741..e658716b4 100644 --- a/test/test_common/test_csr.cc +++ b/test/test_common/test_csr.cc @@ -1,103 +1,103 @@ /** * @file test_csr.cc * * @author Nicolas Richart * * @date creation: Sun Oct 19 2014 * @date last modification: Sun Dec 03 2017 * * @brief Test the CSR (compressed sparse row) data structure * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_csr.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ using namespace akantu; class TestCsrFixture : public ::testing::Test { protected: void SetUp() override { csr.resizeRows(N); csr.clearRows(); for (Int i = 0; i < N; ++i) { UInt nb_cols(UInt(rand() * double(N) / (RAND_MAX + 1.))); nb_cols_per_row.push_back(nb_cols); for (Int j = 0; j < nb_cols; ++j) { ++csr.rowOffset(i); } } csr.countToCSR(); csr.resizeCols(); csr.beginInsertions(); for (Int i = 0; i < N; ++i) { UInt nb_cols = nb_cols_per_row[i]; for (Int j = 0; j < nb_cols; ++j) { csr.insertInRow(i, nb_cols - j); } } csr.endInsertions(); } - std::vector nb_cols_per_row; - CSR csr; - size_t N = 1000; + std::vector nb_cols_per_row; + CSR csr; + Int N = 1000; }; TEST_F(TestCsrFixture, CheckInsertion) { EXPECT_EQ(N, this->csr.getNbRows()); } TEST_F(TestCsrFixture, Iteration) { for (Int i = 0; i < this->csr.getNbRows(); ++i) { auto it = this->csr.begin(i); auto end = this->csr.end(i); UInt nb_cols = this->nb_cols_per_row[i]; for (; it != end; ++it) { EXPECT_EQ(nb_cols, *it); nb_cols--; } EXPECT_EQ(0, nb_cols); } } TEST_F(TestCsrFixture, ReverseIteration) { for (Int i = 0; i < csr.getNbRows(); ++i) { auto it = csr.rbegin(i); auto end = csr.rend(i); UInt nb_cols = nb_cols_per_row[i]; UInt j = nb_cols; for (; it != end; --it) { EXPECT_EQ((nb_cols - j + 1), *it); j--; } EXPECT_EQ(0, j); } } diff --git a/test/test_common/test_tensors.cc b/test/test_common/test_tensors.cc index 55e5ce1fe..637e5b291 100644 --- a/test/test_common/test_tensors.cc +++ b/test/test_common/test_tensors.cc @@ -1,578 +1,579 @@ /** * @file test_tensors.cc * * @author Nicolas Richart * * @date creation: Tue Nov 14 2017 * @date last modification: Tue Feb 05 2019 * * @brief test the tensors types * * * @section LICENSE * * Copyright (©) 2016-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_iterators.hh" #include "aka_types.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; namespace { /* -------------------------------------------------------------------------- */ class TensorConstructorFixture : public ::testing::Test { public: void SetUp() override { - for (auto & r : reference) { + for (auto &r : reference) { r = rand(); // google-test seeds srand() } } void TearDown() override {} - template void compareToRef(const V & v) { + template void compareToRef(const V &v) { for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i], v.data()[i]); } } protected: const int size_{24}; const std::array mat_size{{4, 6}}; // const std::array tens3_size{{4, 2, 3}}; std::array reference; }; /* -------------------------------------------------------------------------- */ class TensorFixture : public TensorConstructorFixture { public: TensorFixture() : vref(reference.data(), size_), mref(reference.data(), mat_size[0], mat_size[1]) {} protected: VectorProxy vref; MatrixProxy mref; }; /* -------------------------------------------------------------------------- */ // Vector ---------------------------------------------------------------------- TEST_F(TensorConstructorFixture, VectorDefaultConstruct) { Vector v; EXPECT_EQ(0, v.size()); EXPECT_EQ(nullptr, v.data()); } TEST_F(TensorConstructorFixture, VectorConstruct1) { Vector v(size_); EXPECT_EQ(size_, v.size()); } TEST_F(TensorConstructorFixture, VectorConstructWrapped) { VectorProxy v(reference.data(), size_); EXPECT_EQ(size_, v.size()); EXPECT_EQ(v.data(), reference.data()); for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i], v(i)); EXPECT_DOUBLE_EQ(reference[i], v[i]); } } TEST_F(TensorConstructorFixture, VectorConstructInitializer) { Vector v{0., 1., 2., 3., 4., 5.}; EXPECT_EQ(6, v.size()); for (int i = 0; i < 6; ++i) { EXPECT_DOUBLE_EQ(i, v(i)); } } TEST_F(TensorConstructorFixture, VectorConstructCopy1) { VectorProxy vref(reference.data(), reference.size()); Vector v(vref); EXPECT_EQ(size_, v.size()); compareToRef(v); } TEST_F(TensorConstructorFixture, VectorConstructProxy1) { VectorProxy vref(reference.data(), reference.size()); EXPECT_EQ(size_, vref.size()); compareToRef(vref); Vector v(vref); EXPECT_EQ(size_, v.size()); compareToRef(v); } /* -------------------------------------------------------------------------- */ TEST_F(TensorFixture, VectorEqual) { Vector v; v = vref; compareToRef(v); EXPECT_EQ(size_, v.size()); } TEST_F(TensorFixture, VectorEqualProxy) { VectorProxy vref_proxy(vref); Vector v; v = vref; compareToRef(v); EXPECT_EQ(size_, v.size()); } TEST_F(TensorFixture, VectorEqualProxy2) { Vector v_store(size_); v_store.zero(); VectorProxy v(v_store.data(), size_); v = vref; compareToRef(v); compareToRef(v_store); } /* -------------------------------------------------------------------------- */ TEST_F(TensorFixture, VectorSet) { Vector v(vref); compareToRef(v); double r = rand(); v.set(r); for (int i = 0; i < size_; ++i) EXPECT_DOUBLE_EQ(r, v[i]); } TEST_F(TensorFixture, VectorClear) { Vector v(vref); compareToRef(v); v.zero(); for (int i = 0; i < size_; ++i) EXPECT_DOUBLE_EQ(0, v[i]); } /* -------------------------------------------------------------------------- */ TEST_F(TensorFixture, VectorDivide) { Vector v; double r = rand(); v = vref / r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] / r, v[i]); } } TEST_F(TensorFixture, VectorMultiply1) { Vector v; double r = rand(); v = vref * r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * r, v[i]); } } TEST_F(TensorFixture, VectorMultiply2) { Vector v; double r = rand(); v = r * vref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * r, v[i]); } } TEST_F(TensorFixture, VectorAddition) { Vector v; v = vref + vref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * 2., v[i]); } } TEST_F(TensorFixture, VectorSubstract) { Vector v; v = vref - vref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(0., v[i]); } } TEST_F(TensorFixture, VectorDivideEqual) { Vector v(vref); double r = rand(); v /= r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] / r, v[i]); } } TEST_F(TensorFixture, VectorMultiplyEqual1) { Vector v(vref); double r = rand(); v *= r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * r, v[i]); } } TEST_F(TensorFixture, VectorMultiplyEqual2) { Vector v(vref); v.array() *= v.array(); for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * reference[i], v[i]); } } TEST_F(TensorFixture, VectorAdditionEqual) { Vector v(vref); v += vref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * 2., v[i]); } } TEST_F(TensorFixture, VectorSubstractEqual) { Vector v(vref); v -= vref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(0., v[i]); } } /* -------------------------------------------------------------------------- */ // Matrix ---------------------------------------------------------------------- TEST_F(TensorConstructorFixture, MatrixDefaultConstruct) { Matrix m; EXPECT_EQ(0, m.size()); EXPECT_EQ(0, m.rows()); EXPECT_EQ(0, m.cols()); EXPECT_EQ(nullptr, m.data()); } TEST_F(TensorConstructorFixture, MatrixConstruct1) { - double r = rand(); Matrix m(mat_size[0], mat_size[1]); EXPECT_EQ(size_, m.size()); EXPECT_EQ(mat_size[0], m.rows()); EXPECT_EQ(mat_size[1], m.cols()); } TEST_F(TensorConstructorFixture, MatrixConstructWrapped) { MatrixProxy m(reference.data(), mat_size[0], mat_size[1]); EXPECT_EQ(size_, m.size()); EXPECT_EQ(mat_size[0], m.rows()); EXPECT_EQ(mat_size[1], m.cols()); for (int i = 0; i < mat_size[0]; ++i) { for (int j = 0; j < mat_size[1]; ++j) { EXPECT_DOUBLE_EQ(reference[i + j * mat_size[0]], m(i, j)); } } compareToRef(m); } TEST_F(TensorConstructorFixture, MatrixConstructInitializer) { Matrix m{{0., 1., 2.}, {3., 4., 5.}}; EXPECT_EQ(6, m.size()); EXPECT_EQ(2, m.rows()); EXPECT_EQ(3, m.cols()); int c = 0; for (int i = 0; i < 2; ++i) { for (int j = 0; j < 3; ++j, ++c) { EXPECT_DOUBLE_EQ(c, m(i, j)); } } } TEST_F(TensorConstructorFixture, MatrixConstructCopy1) { MatrixProxy mref(reference.data(), mat_size[0], mat_size[1]); Matrix m(mref); EXPECT_EQ(size_, m.size()); EXPECT_EQ(mat_size[0], m.rows()); EXPECT_EQ(mat_size[1], m.cols()); compareToRef(m); } TEST_F(TensorConstructorFixture, MatrixConstructProxy1) { MatrixProxy mref(reference.data(), mat_size[0], mat_size[1]); EXPECT_EQ(size_, mref.size()); EXPECT_EQ(mat_size[0], mref.size(0)); EXPECT_EQ(mat_size[1], mref.size(1)); compareToRef(mref); Matrix m(mref); EXPECT_EQ(size_, m.size()); EXPECT_EQ(mat_size[0], m.rows()); EXPECT_EQ(mat_size[1], m.cols()); compareToRef(m); } /* -------------------------------------------------------------------------- */ TEST_F(TensorFixture, MatrixEqual) { Matrix m; m = mref; compareToRef(m); EXPECT_EQ(size_, m.size()); EXPECT_EQ(mat_size[0], m.rows()); EXPECT_EQ(mat_size[1], m.cols()); } TEST_F(TensorFixture, MatrixEqualProxy1) { MatrixProxy mref_proxy(mref.data(), mref.rows(), mref.cols()); Matrix m; m = mref; compareToRef(m); EXPECT_EQ(size_, m.size()); EXPECT_EQ(mat_size[0], m.rows()); EXPECT_EQ(mat_size[1], m.cols()); } TEST_F(TensorFixture, MatrixEqualProxy2) { Matrix m_store(mat_size[0], mat_size[1]); m_store.zero(); MatrixProxy m(m_store.data(), mat_size[0], mat_size[1]); m = mref; compareToRef(m); compareToRef(m_store); } TEST_F(TensorFixture, MatrixEqualSlice) { Matrix m(mat_size[0], mat_size[1]); m.zero(); - for (unsigned int i = 0; i < m.cols(); ++i) { + for (Int i = 0; i < m.cols(); ++i) { m(i) = mref(i); } compareToRef(m); } /* -------------------------------------------------------------------------- */ TEST_F(TensorFixture, MatrixSet) { Matrix m(mref); compareToRef(m); double r = rand(); m.set(r); for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(r, m.array()(i)); } } TEST_F(TensorFixture, MatrixClear) { Matrix m(mref); compareToRef(m); m.zero(); for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(0, m.array()(i)); } } /* -------------------------------------------------------------------------- */ TEST_F(TensorFixture, MatrixDivide) { Matrix m; double r = rand(); m = mref / r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] / r, m.array()(i)); } } TEST_F(TensorFixture, MatrixMultiply1) { Matrix m; double r = rand(); m = mref * r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * r, m.array()(i)); } } TEST_F(TensorFixture, MatrixMultiply2) { Matrix m; double r = rand(); m = r * mref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * r, m.array()(i)); } } TEST_F(TensorFixture, MatrixAddition) { Matrix m; m = mref + mref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * 2., m.array()(i)); } } TEST_F(TensorFixture, MatrixSubstract) { Matrix m; m = mref - mref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(0., m.array()(i)); } } TEST_F(TensorFixture, MatrixDivideEqual) { Matrix m(mref); double r = rand(); m /= r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] / r, m.array()(i)); } } TEST_F(TensorFixture, MatrixMultiplyEqual1) { Matrix m(mref); double r = rand(); m *= r; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * r, m.array()(i)); } } TEST_F(TensorFixture, MatrixAdditionEqual) { Matrix m(mref); m += mref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(reference[i] * 2., m.array()(i)); } } TEST_F(TensorFixture, MatrixSubstractEqual) { Matrix m(mref); m -= mref; for (int i = 0; i < size_; ++i) { EXPECT_DOUBLE_EQ(0., m.array()(i)); } } TEST_F(TensorFixture, MatrixIterator) { Matrix m(mref); UInt col_count = 0; - for (auto && col : m) { + for (auto &&col : m) { VectorProxy col_hand(m.data() + col_count * m.rows(), m.rows()); Vector col_wrap(col); auto comp = (col_wrap - col_hand).lpNorm(); EXPECT_DOUBLE_EQ(0., comp); ++col_count; } } TEST_F(TensorFixture, MatrixIteratorZip) { Matrix m1(mref); Matrix m2(mref); UInt col_count = 0; - for (auto && col : zip(m1, m2)) { + for (auto &&col : zip(m1, m2)) { Vector col1(std::get<0>(col)); Vector col2(std::get<1>(col)); auto comp = (col1 - col2).lpNorm(); EXPECT_DOUBLE_EQ(0., comp); ++col_count; } } #if defined(AKANTU_USE_LAPACK) TEST_F(TensorFixture, MatrixEigs) { Matrix A{ {0, 1., 0, 0}, {1., 0, 0, 0}, {0, 1., 0, 1.}, {0, 0, 4., 0}}; Matrix v; Vector lambda; + lambda.zero(); + v.zero(); A.eig(lambda, v); Vector eigs_ref{2, 1., -1., -2}; auto Av = (A * v).eval(); // Eigen::PermutationMatrix // perm(lambda.size()); perm.setIdentity(); // std::sort(perm.indices().data(), // perm.indices().data() + perm.indices().size(), // [&lambda](const Eigen::Index & a, const Eigen::Index & b) { // return (lambda(a) - lambda(b)) > 0; // }); // std::cout << v << std::endl; // std::cout << lambda << std::endl; // std::cout << v * perm << std::endl; // std::cout << perm.transpose() * lambda << std::endl; // std::cout << (Av(0) - lambda(0) * v(0)).eval() << std::endl; for (int i = 0; i < 4; ++i) { EXPECT_NEAR(eigs_ref(i), lambda(i), 1e-14); } for (int i = 0; i < 4; ++i) { auto lambda_v_minus_a_v = (lambda(i) * v(i) - Av(i)).template lpNorm(); EXPECT_NEAR(lambda_v_minus_a_v, 0., 1e-14); } } #endif /* -------------------------------------------------------------------------- */ } // namespace diff --git a/test/test_fe_engine/test_fe_engine_fixture.hh b/test/test_fe_engine/test_fe_engine_fixture.hh index 07378f5b9..648bd495f 100644 --- a/test/test_fe_engine/test_fe_engine_fixture.hh +++ b/test/test_fe_engine/test_fe_engine_fixture.hh @@ -1,114 +1,113 @@ /** * @file test_fe_engine_fixture.hh * * @author Nicolas Richart * * @date creation: Tue Nov 14 2017 * @date last modification: Wed Nov 18 2020 * * @brief Fixture for feengine tests * * * @section LICENSE * * Copyright (©) 2016-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "test_gtest_utils.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef AKANTU_TEST_FE_ENGINE_FIXTURE_HH_ #define AKANTU_TEST_FE_ENGINE_FIXTURE_HH_ using namespace akantu; /// Generic class for FEEngine tests template class shape_t, ElementKind kind = _ek_regular> class TestFEMBaseFixture : public ::testing::Test { public: static constexpr const ElementType type = type_::value; - static constexpr const size_t dim = ElementClass::getSpatialDimension(); + static constexpr const Int dim = ElementClass::getSpatialDimension(); using FEM = FEEngineTemplate; /// Setup reads mesh corresponding to element type and initializes an FEEngine void SetUp() override { const auto dim = this->dim; mesh = std::make_unique(dim); std::stringstream meshfilename; meshfilename << type << ".msh"; this->readMesh(meshfilename.str()); lower = mesh->getLowerBounds(); upper = mesh->getUpperBounds(); nb_element = this->mesh->getNbElement(type); fem = std::make_unique(*mesh, dim, "my_fem"); nb_quadrature_points_total = GaussIntegrationElement::getNbQuadraturePoints() * nb_element; SCOPED_TRACE(std::to_string(type)); } void TearDown() override { fem.reset(nullptr); mesh.reset(nullptr); } /// Should be reimplemented if further treatment of the mesh is needed virtual void readMesh(std::string file_name) { mesh->read(file_name); } protected: std::unique_ptr fem; std::unique_ptr mesh; - UInt nb_element; - UInt nb_quadrature_points_total; + Int nb_element; + Int nb_quadrature_points_total; Vector lower; Vector upper; }; template class shape_t, ElementKind kind> constexpr const ElementType TestFEMBaseFixture::type; template class shape_t, ElementKind kind> -constexpr const size_t TestFEMBaseFixture::dim; +constexpr const Int TestFEMBaseFixture::dim; /* -------------------------------------------------------------------------- */ /// Base class for test with Lagrange FEEngine and regular elements template using TestFEMFixture = TestFEMBaseFixture; /* -------------------------------------------------------------------------- */ - using fe_engine_types = gtest_list_t; TYPED_TEST_SUITE(TestFEMFixture, fe_engine_types, ); #endif /* AKANTU_TEST_FE_ENGINE_FIXTURE_HH_ */ diff --git a/test/test_model/test_contact_mechanics_model/test_explicit_friction.cc b/test/test_model/test_contact_mechanics_model/test_explicit_friction.cc index 09832f4af..32868c951 100644 --- a/test/test_model/test_contact_mechanics_model/test_explicit_friction.cc +++ b/test/test_model/test_contact_mechanics_model/test_explicit_friction.cc @@ -1,179 +1,179 @@ /** * @file test_explicit_friction.cc * * @author Mohit Pundir * * @date creation: Sun Jun 06 2021 * @date last modification: Sun Jun 06 2021 * * @brief Test contact mechanics with friction * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "contact_mechanics_model.hh" #include "coupler_solid_contact.hh" #include "non_linear_solver.hh" #include "solid_mechanics_model.hh" #include "surface_selector.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ template std::vector arrange(T start, T stop, T step = 1) { std::vector values; for (T value = start; value <= stop; value += step) values.push_back(value); return values; } int main(int argc, char * argv[]) { - UInt max_normal_steps = 2500; - UInt max_shear_steps = 7500; + Int max_normal_steps = 2500; + Int max_shear_steps = 7500; Real max_shear_displacement = 1e-1; Real max_normal_displacement = 2e-2; Real damping_ratio = 0.99; std::string mesh_file = "sliding-block-2D.msh"; std::string material_file = "material-friction.dat"; const Int spatial_dimension = 2; initialize(material_file, argc, argv); Mesh mesh(spatial_dimension); mesh.read(mesh_file); CouplerSolidContact coupler(mesh); auto & solid = coupler.getSolidMechanicsModel(); auto & contact = coupler.getContactMechanicsModel(); auto && material_selector = std::make_shared>("physical_names", solid); solid.setMaterialSelector(material_selector); coupler.initFull(_analysis_method = _explicit_lumped_mass); auto && surface_selector = std::make_shared(mesh); contact.getContactDetector().setSurfaceSelector(surface_selector); solid.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "lower"); solid.applyBC(BC::Dirichlet::FixedValue(0.0, _y), "lower"); Real time_step = solid.getStableTimeStep(); time_step *= 0.05; coupler.setTimeStep(time_step); std::cout << "Stable time increment : " << time_step << " sec " << std::endl; coupler.setBaseName("explicit-friction"); coupler.addDumpFieldVector("displacement"); coupler.addDumpFieldVector("normals"); coupler.addDumpFieldVector("contact_force"); coupler.addDumpFieldVector("tangential_force"); coupler.addDumpFieldVector("external_force"); coupler.addDumpFieldVector("internal_force"); coupler.addDumpField("gaps"); coupler.addDumpField("areas"); coupler.addDumpField("blocked_dofs"); coupler.addDumpField("strain"); coupler.addDumpField("stress"); coupler.addDumpField("contact_state"); auto & velocity = solid.getVelocity(); auto & gaps = contact.getGaps(); auto xi = arrange(0, 1, 1. / max_shear_steps); std::vector shear_displacements; std::transform(xi.begin(), xi.end(), std::back_inserter(shear_displacements), [&](Real & p) -> Real { return 0. + (max_shear_displacement)*pow(p, 3) * (10 - 15 * p + 6 * pow(p, 2)); }); auto normal_xi = arrange(0, 1, 1. / max_normal_steps); std::vector normal_displacements; std::transform(normal_xi.begin(), normal_xi.end(), std::back_inserter(normal_displacements), [&](Real & p) -> Real { return 0. + (max_normal_displacement)*pow(p, 3) * (10 - 15 * p + 6 * pow(p, 2)); }); auto max_steps = max_normal_steps + max_shear_steps; auto & contact_nodes = surface_selector->getSlaveList(); auto & tangential_traction = contact.getTangentialTractions(); for (Int s : arange(max_steps)) { if (s < max_normal_steps) { solid.applyBC(BC::Dirichlet::FixedValue(-normal_displacements[s], _y), "loading"); } else { solid.applyBC(BC::Dirichlet::FixedValue( shear_displacements[s - max_normal_steps], _x), "loading"); } coupler.solveStep(); for (auto && tuple : zip(gaps, make_view(velocity, spatial_dimension))) { auto & gap = std::get<0>(tuple); auto & vel = std::get<1>(tuple); if (gap > 0) { vel *= damping_ratio; } } if (s % 100 == 0) { coupler.dump(); } auto sum = std::accumulate(tangential_traction.begin(), tangential_traction.end(), 0.0); auto num_tang_traction = std::abs(sum) / contact_nodes.size(); Real exp_tang_traction = 0.3 * 1.4e6; Real error = std::abs(num_tang_traction - exp_tang_traction) / exp_tang_traction; if (error > 1e-3 and num_tang_traction > exp_tang_traction) { std::cerr << error << "----" << num_tang_traction << std::endl; return EXIT_FAILURE; } } coupler.dump(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_phase_field_model/test_multi_material.cc b/test/test_model/test_phase_field_model/test_multi_material.cc index a1ac83a88..92da08464 100644 --- a/test/test_model/test_phase_field_model/test_multi_material.cc +++ b/test/test_model/test_phase_field_model/test_multi_material.cc @@ -1,127 +1,127 @@ /** * @file test_multi_material.cc * * @author Mohit Pundir * * @date creation: Wed Feb 24 2021 * @date last modification: Sun Feb 28 2021 * * @brief test of the class PhaseFieldModel on the 2d square * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "coupler_solid_phasefield.hh" #include "material.hh" #include "material_phasefield.hh" #include "non_linear_solver.hh" #include "phase_field_model.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; const Int spatial_dimension = 2; /* -------------------------------------------------------------------------- */ void applyDisplacement(SolidMechanicsModel &, Real &); /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { initialize("material_multiple.dat", argc, argv); Mesh mesh(spatial_dimension); mesh.read("test_two_element.msh"); CouplerSolidPhaseField coupler(mesh); auto & model = coupler.getSolidMechanicsModel(); auto & phase = coupler.getPhaseFieldModel(); auto && mat_selector = std::make_shared>("physical_names", model); model.setMaterialSelector(mat_selector); model.initFull(_analysis_method = _explicit_lumped_mass); Real time_step = model.getStableTimeStep(); time_step *= 0.8; model.setTimeStep(time_step); auto && selector = std::make_shared>( "physical_names", phase); phase.setPhaseFieldSelector(selector); phase.initFull(_analysis_method = _static); model.setBaseName("multi_material"); model.addDumpField("stress"); model.addDumpField("grad_u"); model.addDumpField("damage"); model.addDumpFieldVector("displacement"); model.addDumpField("blocked_dofs"); model.dump(); - UInt nbSteps = 1000; + Int nbSteps = 1000; Real increment = 1e-4; for (Int s = 0; s < nbSteps; ++s) { Real axial_strain = increment * s; applyDisplacement(model, axial_strain); coupler.solve(); model.dump(); } finalize(); return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ void applyDisplacement(SolidMechanicsModel & model, Real & increment) { auto & displacement = model.getDisplacement(); auto & positions = model.getMesh().getNodes(); auto & blocked_dofs = model.getBlockedDOFs(); for (Int n = 0; n < model.getMesh().getNbNodes(); ++n) { if (positions(n, 1) == -1) { displacement(n, 1) = 0; blocked_dofs(n, 1) = true; displacement(n, 0) = 0; blocked_dofs(n, 0) = true; } else if (positions(n, 1) == 1) { displacement(n, 0) = 0; displacement(n, 1) = increment; blocked_dofs(n, 0) = true; blocked_dofs(n, 1) = true; } else { displacement(n, 0) = 0; blocked_dofs(n, 0) = true; } } } diff --git a/test/test_model/test_phase_field_model/test_phase_solid_coupling.cc b/test/test_model/test_phase_field_model/test_phase_solid_coupling.cc index d4c572832..7cbd2f82c 100644 --- a/test/test_model/test_phase_field_model/test_phase_solid_coupling.cc +++ b/test/test_model/test_phase_field_model/test_phase_solid_coupling.cc @@ -1,273 +1,273 @@ /** * @file test_phase_solid_coupling.cc * * @author Mohit Pundir * * @date creation: Sun Jan 06 2019 * @date last modification: Wed Mar 03 2021 * * @brief test of the class PhaseFieldModel on the 2d square * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "material_phasefield.hh" #include "non_linear_solver.hh" #include "phase_field_model.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; const Int spatial_dimension = 2; /* -------------------------------------------------------------------------- */ void applyDisplacement(SolidMechanicsModel &, Real &); void computeStrainOnQuadPoints(SolidMechanicsModel &, PhaseFieldModel &, GhostType); void computeDamageOnQuadPoints(SolidMechanicsModel &, PhaseFieldModel &, GhostType); void gradUToEpsilon(const Matrix &, Matrix &); /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { std::ofstream os("data.csv"); os << "#strain stress damage analytical_sigma analytical_damage" << std::endl; initialize("material_coupling.dat", argc, argv); Mesh mesh(spatial_dimension); mesh.read("test_one_element.msh"); SolidMechanicsModel model(mesh); model.initFull(_analysis_method = _static); PhaseFieldModel phase(mesh); auto && selector = std::make_shared>( "physical_names", phase); phase.setPhaseFieldSelector(selector); phase.initFull(_analysis_method = _static); model.setBaseName("phase_solid"); model.addDumpField("stress"); model.addDumpField("grad_u"); model.addDumpFieldVector("displacement"); model.addDumpField("damage"); model.dump(); - UInt nbSteps = 1000; + Int nbSteps = 1000; Real increment = 1e-4; auto & stress = model.getMaterial(0).getArray("stress", _quadrangle_4); auto & damage = model.getMaterial(0).getArray("damage", _quadrangle_4); Real analytical_damage{0.}; Real analytical_sigma{0.}; auto & phasefield = phase.getPhaseField(0); const Real E = phasefield.getParam("E"); const Real nu = phasefield.getParam("nu"); Real c22 = E * (1 - nu) / ((1 + nu) * (1 - 2 * nu)); const Real gc = phasefield.getParam("gc"); const Real l0 = phasefield.getParam("l0"); Real error_stress{0.}; Real error_damage{0.}; for (Int s = 0; s < nbSteps; ++s) { Real axial_strain = increment * s; applyDisplacement(model, axial_strain); model.solveStep(); computeStrainOnQuadPoints(model, phase, _not_ghost); phase.solveStep(); computeDamageOnQuadPoints(model, phase, _not_ghost); model.assembleInternalForces(); analytical_damage = axial_strain * axial_strain * c22 / (gc / l0 + axial_strain * axial_strain * c22); analytical_sigma = c22 * axial_strain * (1 - analytical_damage) * (1 - analytical_damage); error_stress = std::abs(analytical_sigma - stress(0, 3)) / analytical_sigma; error_damage = std::abs(analytical_damage - damage(0)) / analytical_damage; if (error_damage > 1e-8 and error_stress > 1e-8) { return EXIT_FAILURE; } os << axial_strain << " " << stress(0, 3) << " " << damage(0) << " " << analytical_sigma << " " << analytical_damage << " " << error_stress << " " << error_damage << std::endl; model.dump(); } os.close(); finalize(); return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ void applyDisplacement(SolidMechanicsModel & model, Real & increment) { auto & displacement = model.getDisplacement(); auto & positions = model.getMesh().getNodes(); auto & blocked_dofs = model.getBlockedDOFs(); for (Int n = 0; n < model.getMesh().getNbNodes(); ++n) { if (positions(n, 1) == -0.5) { displacement(n, 0) = 0; displacement(n, 1) = 0; blocked_dofs(n, 0) = true; blocked_dofs(n, 1) = true; } else { displacement(n, 0) = 0; displacement(n, 1) = increment; blocked_dofs(n, 0) = true; blocked_dofs(n, 1) = true; } } } /* -------------------------------------------------------------------------- */ void computeStrainOnQuadPoints(SolidMechanicsModel & solid, PhaseFieldModel & phase, GhostType ghost_type) { auto & mesh = solid.getMesh(); auto nb_materials = solid.getNbMaterials(); auto nb_phasefields = phase.getNbPhaseFields(); AKANTU_DEBUG_ASSERT( nb_phasefields == nb_materials, "The number of phasefields and materials should be equal"); for (auto index : arange(nb_materials)) { auto & material = solid.getMaterial(index); for (auto index2 : arange(nb_phasefields)) { auto & phasefield = phase.getPhaseField(index2); if (phasefield.getName() == material.getName()) { auto & strain_on_qpoints = phasefield.getStrain(); auto & gradu_on_qpoints = material.getGradU(); for (const auto & type : mesh.elementTypes(spatial_dimension, ghost_type)) { auto & strain_on_qpoints_vect = strain_on_qpoints(type, ghost_type); auto & gradu_on_qpoints_vect = gradu_on_qpoints(type, ghost_type); for (auto && values : zip(make_view(strain_on_qpoints_vect, spatial_dimension, spatial_dimension), make_view(gradu_on_qpoints_vect, spatial_dimension, spatial_dimension))) { auto & strain = std::get<0>(values); auto & grad_u = std::get<1>(values); Material::gradUToEpsilon(grad_u, strain); } } break; } } } } /* -------------------------------------------------------------------------- */ void computeDamageOnQuadPoints(SolidMechanicsModel & solid, PhaseFieldModel & phase, GhostType ghost_type) { auto & fem = phase.getFEEngine(); auto & mesh = phase.getMesh(); auto nb_materials = solid.getNbMaterials(); auto nb_phasefields = phase.getNbPhaseFields(); AKANTU_DEBUG_ASSERT( nb_phasefields == nb_materials, "The number of phasefields and materials should be equal"); for (auto index : arange(nb_materials)) { auto & material = solid.getMaterial(index); for (auto index2 : arange(nb_phasefields)) { auto & phasefield = phase.getPhaseField(index2); if (phasefield.getName() == material.getName()) { switch (spatial_dimension) { case 1: { auto & mat = dynamic_cast &>(material); auto & solid_damage = mat.getDamage(); for (const auto & type : mesh.elementTypes(spatial_dimension, ghost_type)) { auto & damage_on_qpoints_vect = solid_damage(type, ghost_type); fem.interpolateOnIntegrationPoints( phase.getDamage(), damage_on_qpoints_vect, 1, type, ghost_type); } break; } case 2: { auto & mat = dynamic_cast &>(material); auto & solid_damage = mat.getDamage(); for (const auto & type : mesh.elementTypes(spatial_dimension, ghost_type)) { auto & damage_on_qpoints_vect = solid_damage(type, ghost_type); fem.interpolateOnIntegrationPoints( phase.getDamage(), damage_on_qpoints_vect, 1, type, ghost_type); } break; } default: break; } } } } } /* -------------------------------------------------------------------------- */ void gradUToEpsilon(const Matrix & grad_u, Matrix & epsilon) { for (Int i = 0; i < spatial_dimension; ++i) { for (Int j = 0; j < spatial_dimension; ++j) epsilon(i, j) = 0.5 * (grad_u(i, j) + grad_u(j, i)); } } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_buildfragments/test_cohesive_buildfragments.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_buildfragments/test_cohesive_buildfragments.cc index 1f9b8d656e..80f0b1915 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_buildfragments/test_cohesive_buildfragments.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_buildfragments/test_cohesive_buildfragments.cc @@ -1,183 +1,183 @@ /** * @file test_cohesive_buildfragments.cc * * @author Marco Vocialta * * @date creation: Sun Oct 19 2014 * @date last modification: Thu May 09 2019 * * @brief Test for cohesive elements * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "fragment_manager.hh" #include "material_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char * argv[]) { initialize("material.dat", argc, argv); Math::setTolerance(1e-14); const Int spatial_dimension = 2; - const UInt max_steps = 200; + const Int max_steps = 200; Real strain_rate = 1.e5; ElementType type = _quadrangle_4; Real L = 0.03; Real theoretical_mass = L * L / 20. * 2500; ElementType type_facet = Mesh::getFacetType(type); ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); Mesh mesh(spatial_dimension); mesh.read("mesh.msh"); SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull(_analysis_method = _explicit_lumped_mass, _is_extrinsic = true); Real time_step = model.getStableTimeStep() * 0.05; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; Real disp_increment = strain_rate * L / 2. * time_step; model.assembleMassLumped(); Array & velocity = model.getVelocity(); const Array & position = mesh.getNodes(); - UInt nb_nodes = mesh.getNbNodes(); + Int nb_nodes = mesh.getNbNodes(); /// initial conditions for (Int n = 0; n < nb_nodes; ++n) velocity(n, 0) = strain_rate * position(n, 0); /// boundary conditions model.applyBC(BC::Dirichlet::FixedValue(0, _x), "Left_side"); model.applyBC(BC::Dirichlet::FixedValue(0, _x), "Right_side"); UInt cohesive_index = 1; UInt nb_quad_per_facet = model.getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); MaterialCohesive & mat_cohesive = dynamic_cast(model.getMaterial(cohesive_index)); const Array & damage = mat_cohesive.getDamage(type_cohesive); FragmentManager fragment_manager(model, false); const Array & fragment_mass = fragment_manager.getMass(); /// Main loop for (Int s = 1; s <= max_steps; ++s) { model.checkCohesiveStress(); model.solveStep(); /// apply boundary conditions model.applyBC(BC::Dirichlet::IncrementValue(-disp_increment, _x), "Left_side"); model.applyBC(BC::Dirichlet::IncrementValue(disp_increment, _x), "Right_side"); if (s % 1 == 0) { // model.dump(); std::cout << "passing step " << s << "/" << max_steps << std::endl; fragment_manager.computeAllData(); /// check number of fragments - UInt nb_fragment_num = fragment_manager.getNbFragment(); + auto nb_fragment_num = fragment_manager.getNbFragment(); - UInt nb_cohesive_elements = mesh.getNbElement(type_cohesive); + auto nb_cohesive_elements = mesh.getNbElement(type_cohesive); - UInt nb_fragment = 1; + Int nb_fragment = 1; for (Int el = 0; el < nb_cohesive_elements; ++el) { UInt q = 0; while (q < nb_quad_per_facet && Math::are_float_equal(damage(el * nb_quad_per_facet + q), 1)) ++q; if (q == nb_quad_per_facet) { ++nb_fragment; } } if (nb_fragment != nb_fragment_num) { std::cout << "The number of fragments is wrong!" << std::endl; return EXIT_FAILURE; } /// check mass computation Real total_mass = 0.; for (Int frag = 0; frag < nb_fragment_num; ++frag) { total_mass += fragment_mass(frag); } if (!Math::are_float_equal(theoretical_mass, total_mass)) { std::cout << "The fragments' mass is wrong!" << std::endl; return EXIT_FAILURE; } } } model.dump(); /// check velocities - UInt nb_fragment = fragment_manager.getNbFragment(); + auto nb_fragment = fragment_manager.getNbFragment(); const Array & fragment_velocity = fragment_manager.getVelocity(); const Array & fragment_center = fragment_manager.getCenterOfMass(); Real fragment_length = L / nb_fragment; Real initial_position = -L / 2. + fragment_length / 2.; for (Int frag = 0; frag < nb_fragment; ++frag) { Real theoretical_center = initial_position + fragment_length * frag; if (!Math::are_float_equal(fragment_center(frag, 0), theoretical_center)) { std::cout << "The fragments' center is wrong!" << std::endl; return EXIT_FAILURE; } Real initial_vel = fragment_center(frag, 0) * strain_rate; Math::setTolerance(100); if (!Math::are_float_equal(fragment_velocity(frag), initial_vel)) { std::cout << "The fragments' velocity is wrong!" << std::endl; return EXIT_FAILURE; } } finalize(); std::cout << "OK: test_cohesive_buildfragments was passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_energies/test_solid_mechanics_model_work_quasistatic.cc b/test/test_model/test_solid_mechanics_model/test_energies/test_solid_mechanics_model_work_quasistatic.cc index 63bca3231..520921a97 100644 --- a/test/test_model/test_solid_mechanics_model/test_energies/test_solid_mechanics_model_work_quasistatic.cc +++ b/test/test_model/test_solid_mechanics_model/test_energies/test_solid_mechanics_model_work_quasistatic.cc @@ -1,147 +1,147 @@ /** * @file test_solid_mechanics_model_work_quasistatic.cc * * @author Tobias Brink * * @date creation: Wed Nov 29 2017 * @date last modification: Wed Dec 04 2019 * * @brief test work in quasistatic * * * @section LICENSE * * Copyright (©) 2016-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * * @section description * * Assuming that the potential energy of a linear elastic material * works correctly, the work in a static simulation must equal the * potential energy of the material. Since the work in static is an * infinitesimal work Fds, we need to integrate by increasing F from 0 * to F_final in steps. This test uses one Dirichlet boundary * condition (with u = 0.0, 0.1, and -0.1) and one Neumann boundary * condition for F on the opposite side. The final work must be the * same for all u. * */ /* -------------------------------------------------------------------------- */ #include "../test_solid_mechanics_model_fixture.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; namespace { TYPED_TEST(TestSMMFixture, WorkQuasistatic) { const auto spatial_dimension = this->spatial_dimension; getStaticParser().parse("test_solid_mechanics_model_" "work_material.dat"); /// model initialization this->model->initFull(_analysis_method = _static); /// Create a node group for Neumann BCs. auto & apply_force_grp = this->mesh->createNodeGroup("apply_force"); auto & fixed_grp = this->mesh->createNodeGroup("fixed"); const auto & pos = this->mesh->getNodes(); auto & flags = this->model->getBlockedDOFs(); auto & lower = this->mesh->getLowerBounds(); auto & upper = this->mesh->getUpperBounds(); - UInt i = 0; + Int i = 0; for (auto && data : zip(make_view(pos, spatial_dimension), make_view(flags, spatial_dimension))) { const auto & posv = std::get<0>(data); auto & flag = std::get<1>(data); if (posv(_x) > upper(_x) - 1e-6) { apply_force_grp.add(i); } else if (posv(_x) < lower(_x) + 1e-6) { fixed_grp.add(i); if ((spatial_dimension > 1) and (posv(_y) < lower(_y) + 1e-6)) { flag(_y) = true; if ((spatial_dimension > 2) and (posv(_z) < lower(_z) + 1e-6)) { flag(_z) = true; } } } ++i; } this->mesh->createElementGroupFromNodeGroup("el_apply_force", "apply_force", spatial_dimension - 1); this->mesh->createElementGroupFromNodeGroup("el_fixed", "fixed", spatial_dimension - 1); std::vector displacements{0.0, 0.1, -0.1}; for (auto && u : displacements) { this->model->applyBC(BC::Dirichlet::FixedValue(u, _x), "el_fixed"); Vector surface_traction(spatial_dimension); Real work = 0.0; Real Epot; static const UInt N = 100; for (Int i = 0; i <= N; ++i) { this->model->getExternalForce().zero(); // reset external forces to zero surface_traction(_x) = (1.0 * i) / N; if (spatial_dimension == 1) { // \TODO: this is a hack to work // around non-implemented // BC::Neumann::FromTraction for 1D auto & force = this->model->getExternalForce(); for (auto && pair : zip(make_view(pos, spatial_dimension), make_view(force, spatial_dimension))) { auto & posv = std::get<0>(pair); auto & forcev = std::get<1>(pair); if (posv(_x) > upper(_x) - 1e-6) { forcev(_x) = surface_traction(_x); } } } else { this->model->applyBC(BC::Neumann::FromTraction(surface_traction), "el_apply_force"); } /// Solve. this->model->solveStep(); Epot = this->model->getEnergy("potential"); // In static, this is infinitesimal work! auto Fds = this->model->getEnergy("external work"); work += Fds; // integrate /// Check that no work was done for zero force. if (i == 0) { EXPECT_NEAR(work, 0.0, 1e-12); } } // Due to the finite integration steps, we make a rather large error // in our work integration, thus the allowed delta is 1e-2. EXPECT_NEAR(work, Epot, 1e-2); } } } // namespace diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_dynamics.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_dynamics.cc index c9c8cc91a..ab0d666f5 100644 --- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_dynamics.cc +++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_dynamics.cc @@ -1,371 +1,371 @@ /** * @file test_structural_mechanics_model_bernoulli_beam_dynamics.cc * * @author Sébastien Hartmann * @author Nicolas Richart * * @date creation: Sun Oct 19 2014 * @date last modification: Mon Mar 15 2021 * * @brief Test for _bernouilli_beam in dynamic * * * @section LICENSE * * Copyright (©) 2014-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "test_structural_mechanics_model_fixture.hh" /* -------------------------------------------------------------------------- */ #include "dof_manager.hh" #include "mesh_accessor.hh" #include "non_linear_solver_newton_raphson.hh" #include "structural_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ static Real analytical_solution(Real time, Real L, Real rho, Real E, __attribute__((unused)) Real A, Real I, Real F) { Real omega = M_PI * M_PI / L / L * sqrt(E * I / rho); Real sum = 0.; - UInt i = 5; + Int i = 5; for (Int n = 1; n <= i; n += 2) { sum += (1. - cos(n * n * omega * time)) / pow(n, 4); } return 2. * F * pow(L, 3) / pow(M_PI, 4) / E / I * sum; } template class TestStructBernoulliDynamic : public TestStructuralFixture { using parent = TestStructuralFixture; public: const UInt nb_element{40}; const Real L{2}; const Real le{L / nb_element}; const UInt nb_nodes{nb_element + 1}; const Real F{1e4}; StructuralMaterial mat; void readMesh(std::string /*filename*/) override { MeshAccessor mesh_accessor(*this->mesh); auto & nodes = mesh_accessor.getNodes(); nodes.resize(nb_nodes); nodes.set(0.); for (auto && data : enumerate(make_view(nodes, this->spatial_dimension))) { auto & node = std::get<1>(data); Int i = std::get<0>(data); node[_x] = i * le; } this->mesh->addConnectivityType(parent::type); auto & connectivities = mesh_accessor.getConnectivity(parent::type); connectivities.resize(nb_element); for (auto && data : enumerate(make_view(connectivities, 2))) { Idx i = std::get<0>(data); auto & connectivity = std::get<1>(data); connectivity = Vector{i, i + 1}; } mesh_accessor.makeReady(); } void setNormals() override { if (this->spatial_dimension != 3) { return; } auto & normals = this->mesh->template getData("extra_normal", parent::type); normals.resize(nb_element); for (auto && normal : make_view(normals, this->spatial_dimension)) { normal = Vector{0., 0., 1.}; } } AnalysisMethod getAnalysisMethod() const override { return _implicit_dynamic; } void addMaterials() override { this->mat.E = 1e9; this->mat.rho = 10; this->mat.I = 1; this->mat.Iz = 1; this->mat.Iy = 1; this->mat.A = 1; this->mat.GJ = 1; this->model->addMaterial(mat); } void setDirichletBCs() override { auto & boundary = this->model->getBlockedDOFs(); boundary.set(false); boundary(0, _x) = true; boundary(0, _y) = true; boundary(nb_nodes - 1, _y) = true; if (this->spatial_dimension == 3) { boundary(0, _z) = true; boundary(nb_nodes - 1, _z) = true; } } void setNeumannBCs() override { auto node_to_print = nb_nodes / 2; // Forces auto & forces = this->model->getExternalForce(); forces.zero(); forces(node_to_print, _y) = F; } void assignMaterials() override { this->model->getElementMaterial(parent::type).set(0); } }; using beam_types = gtest_list_t, element_type_t<_bernoulli_beam_3>>>; TYPED_TEST_SUITE(TestStructBernoulliDynamic, beam_types, ); template void getElementMassMatrix(const StructuralMaterial & /*material*/, Real /*l*/, Matrix & /*M*/) {} template void getElementStifnessMatrix(const StructuralMaterial & /*material*/, Real /*l*/, Matrix & /*M*/) {} template <> void getElementMassMatrix>( const StructuralMaterial & material, Real l, Matrix & M) { auto A = material.A; auto rho = material.rho; // clang-format off M = rho * A * l / 420. * Matrix({ {140, 0, 0, 70, 0, 0}, { 0, 156, 22*l, 0, 54, -13*l}, { 0, 22*l, 4*l*l, 0, 13*l, -3*l*l}, { 70, 0, 0, 140, 0, 0}, { 0, 54, 13*l, 0, 156, -22*l}, { 0,-13*l, -3*l*l, 0, -22*l, 4*l*l}}); // clang-format on } template <> void getElementStifnessMatrix>( const StructuralMaterial & material, Real l, Matrix & K) { auto E = material.E; auto A = material.A; auto I = material.I; auto l_2 = l * l; auto l_3 = l * l * l; // clang-format off K = Matrix({ { E*A/l, 0, 0, -E*A/l, 0, 0}, { 0, 12*E*I/l_3, 6*E*I/l_2, 0, -12*E*I/l_3, 6*E*I/l_2}, { 0, 6*E*I/l_2, 4*E*I/l, 0, -6*E*I/l_2, 2*E*I/l}, {-E*A/l, 0, 0, E*A/l, 0, 0}, { 0, -12*E*I/l_3, -6*E*I/l_2, 0, 12*E*I/l_3, -6*E*I/l_2}, { 0, 6*E*I/l_2, 2*E*I/l, 0, -6*E*I/l_2, 4*E*I/l}}); // clang-format on } template <> void getElementMassMatrix>( const StructuralMaterial & material, Real l, Matrix & M) { auto A = material.A; auto rho = material.rho; // clang-format off M = rho * A * l / 420. * Matrix({ {140, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0}, { 0, 156, 0, 0, 0, 22*l, 0, 54, 0, 0, 0, -13*l}, { 0, 0, 156, 0, -22*l, 0, 0, 0, 54, 0, 13*l, 0}, { 0, 0, 0, 140, 0, 0, 0, 0, 0, 70, 0, 0}, { 0, 0, -22*l, 0, 4*l*l, 0, 0, 0, -13*l, 0, -3*l*l, 0}, { 0, 22*l, 0, 0, 0, 4*l*l, 0, 13*l, 0, 0, 0, -3*l*l}, { 70, 0, 0, 0, 0, 0, 140, 0, 0, 0, 0, 0}, { 0, 54, 0, 0, 0, 13*l, 0, 156, 0, 0, 0, -22*l}, { 0, 0, 54, 0, -13*l, 0, 0, 0, 156, 0, 22*l, 0}, { 0, 0, 0, 70, 0, 0, 0, 0, 0, 140, 0, 0}, { 0, 0, 13*l, 0, -3*l*l, 0, 0, 0, 22*l, 0, 4*l*l, 0}, { 0, -13*l, 0, 0, 0, -3*l*l, 0, -22*l, 0, 0, 0, 4*l*l}}); // clang-format on } template <> void getElementStifnessMatrix>( const StructuralMaterial & material, Real l, Matrix & K) { auto E = material.E; auto A = material.A; auto Iy = material.Iy; auto Iz = material.Iz; auto GJ = material.GJ; auto a1 = E * A / l; auto b1 = 12 * E * Iz / l / l / l; auto b2 = 6 * E * Iz / l / l; auto b3 = 4 * E * Iz / l; auto b4 = 2 * E * Iz / l; auto c1 = 12 * E * Iy / l / l / l; auto c2 = 6 * E * Iy / l / l; auto c3 = 4 * E * Iy / l; auto c4 = 2 * E * Iy / l; auto d1 = GJ / l; // clang-format off K = Matrix({ { a1, 0, 0, 0, 0, 0, -a1, 0, 0, 0, 0, 0}, { 0, b1, 0, 0, 0, b2, 0, -b1, 0, 0, 0, b2}, { 0, 0, c1, 0, -c2, 0, 0, 0, -c1, 0, -c2, 0}, { 0, 0, 0, d1, 0, 0, 0, 0, 0, -d1, 0, 0}, { 0, 0, -c2, 0, c3, 0, 0, 0, c2, 0, c4, 0}, { 0, b2, 0, 0, 0, b3, 0, -b2, 0, 0, 0, b4}, { -a1, 0, 0, 0, 0, 0, a1, 0, 0, 0, 0, 0}, { 0, -b1, 0, 0, 0, -b2, 0, b1, 0, 0, 0, -b2}, { 0, 0, -c1, 0, c2, 0, 0, 0, c1, 0, c2, 0}, { 0, 0, 0, -d1, 0, 0, 0, 0, 0, d1, 0, 0}, { 0, 0, -c2, 0, c4, 0, 0, 0, c2, 0, c3, 0}, { 0, b2, 0, 0, 0, b4, 0, -b2, 0, 0, 0, b3}}); // clang-format on } TYPED_TEST(TestStructBernoulliDynamic, TestBeamMatrices) { this->model->assembleMatrix("M"); this->model->assembleMatrix("K"); const auto & K = this->model->getDOFManager().getMatrix("K"); const auto & M = this->model->getDOFManager().getMatrix("M"); Matrix Ka(this->nb_nodes * this->ndof, this->nb_nodes * this->ndof); Matrix Ma(this->nb_nodes * this->ndof, this->nb_nodes * this->ndof); Ka.zero(); Ma.zero(); Matrix Ke(this->ndof * 2, this->ndof * 2); Matrix Me(this->ndof * 2, this->ndof * 2); getElementMassMatrix(this->mat, this->le, Me); getElementStifnessMatrix(this->mat, this->le, Ke); auto assemble = [&](auto && nodes, auto && M, auto && Me) { auto n1 = nodes[0]; auto n2 = nodes[1]; for (auto i : arange(this->ndof)) { for (auto j : arange(this->ndof)) { M(n1 * this->ndof + i, n1 * this->ndof + j) += Me(i, j); M(n2 * this->ndof + i, n2 * this->ndof + j) += Me(this->ndof + i, this->ndof + j); M(n1 * this->ndof + i, n2 * this->ndof + j) += Me(i, this->ndof + j); M(n2 * this->ndof + i, n1 * this->ndof + j) += Me(this->ndof + i, j); } } }; auto && connectivities = this->mesh->getConnectivity(this->type); for (auto && connectivity : make_view(connectivities, 2)) { assemble(connectivity, Ka, Ke); assemble(connectivity, Ma, Me); } auto tol = 1e-13; auto Ka_max = Ka.template lpNorm(); auto Ma_max = Ma.template lpNorm(); for (auto i : arange(Ka.rows())) { for (auto j : arange(Ka.cols())) { EXPECT_NEAR(Ka(i, j), K(i, j), tol * Ka_max); EXPECT_NEAR(Ma(i, j), M(i, j), tol * Ma_max); } } } TYPED_TEST(TestStructBernoulliDynamic, TestBeamOscilation) { Real time_step = 1e-6; this->model->setTimeStep(time_step); auto & solver = this->model->getNonLinearSolver(); solver.set("max_iterations", 100); solver.set("threshold", 1e-8); solver.set("convergence_type", SolveConvergenceCriteria::_solution); auto node_to_print = this->nb_nodes / 2; auto & d = this->model->getDisplacement()(node_to_print, _y); std::ofstream pos; std::string filename = "position" + std::to_string(this->type) + ".csv"; pos.open(filename); if (not pos.good()) { AKANTU_ERROR("Cannot open file \"position.csv\""); } pos << "id,time,position,solution" << std::endl; //#define debug #ifdef debug this->model->addDumpFieldVector("displacement"); this->model->addDumpField("blocked_dofs"); this->model->addDumpFieldVector("external_force"); this->model->addDumpFieldVector("internal_force"); this->model->addDumpFieldVector("acceleration"); this->model->addDumpFieldVector("velocity"); this->model->dump(); #endif this->model->getDisplacement().set(0.); Real tol = 1e-6; Real time = 0.; for (Int s = 1; s < 300; ++s) { EXPECT_NO_THROW(this->model->solveStep()); time = s * time_step; auto da = analytical_solution(time, this->L, this->mat.rho, this->mat.E, this->mat.A, this->mat.Iy, this->F); pos << s << "," << time << "," << d << "," << da << std::endl; #ifdef debug this->model->dump(); #endif EXPECT_NEAR(d, da, tol); } } diff --git a/test/test_solver/test_sparse_solver_mumps.cc b/test/test_solver/test_sparse_solver_mumps.cc index 44dfadf48..3d849f0c6 100644 --- a/test/test_solver/test_sparse_solver_mumps.cc +++ b/test/test_solver/test_sparse_solver_mumps.cc @@ -1,169 +1,169 @@ /** * @file test_sparse_solver_mumps.cc * * @author Nicolas Richart * * @date creation: Fri May 19 2017 * @date last modification: Sun Dec 30 2018 * * @brief test the matrix vector product in parallel * * * @section LICENSE * * Copyright (©) 2016-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dof_synchronizer.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_accessor.hh" #include "mesh_partition_scotch.hh" #include "sparse_matrix_aij.hh" #include "sparse_solver_mumps.hh" #include "terms_to_assemble.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ void genMesh(Mesh & mesh, UInt nb_nodes); /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { initialize(argc, argv); const Int spatial_dimension = 1; - const UInt nb_global_dof = 11; + const Int nb_global_dof = 11; const auto & comm = Communicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); Mesh mesh(spatial_dimension); if (prank == 0) { genMesh(mesh, nb_global_dof); RandomGenerator::seed(1496137735); } else { RandomGenerator::seed(2992275470); } mesh.distribute(); UInt node = 0; for (auto pos : mesh.getNodes()) { std::cout << prank << " " << node << " pos: " << pos << " [" << mesh.getNodeGlobalId(node) << "] " << mesh.getNodeFlag(node) << std::endl; ++node; } UInt nb_nodes = mesh.getNbNodes(); DOFManagerDefault dof_manager(mesh, "test_dof_manager"); Array x(nb_nodes); dof_manager.registerDOFs("x", x, _dst_nodal); const auto & local_equation_number = dof_manager.getLocalEquationsNumbers("x"); auto & A = dof_manager.getNewMatrix("A", _symmetric); Array b(nb_nodes); TermsToAssemble terms("x", "x"); for (Int i = 0; i < nb_nodes; ++i) { if (dof_manager.isLocalOrMasterDOF(i)) { auto li = local_equation_number(i); auto gi = dof_manager.localToGlobalEquationNumber(li); terms(i, i) = 1. / (1. + gi); } } dof_manager.assemblePreassembledMatrix("A", terms); std::stringstream str; str << "Matrix_" << prank << ".mtx"; A.saveMatrix(str.str()); for (Int n = 0; n < nb_nodes; ++n) { b(n) = 1.; } SparseSolverMumps solver(dof_manager, "A"); solver.solve(x, b); auto && check = [&](auto && xs) { debug::setDebugLevel(dblTest); std::cout << xs << std::endl; debug::setDebugLevel(dblWarning); UInt d = 1.; for (auto x : xs) { if (std::abs(x - d) / d > 1e-15) AKANTU_EXCEPTION("Error in the solution: " << x << " != " << d << " [" << (std::abs(x - d) / d) << "]."); ++d; } }; if (psize > 1) { auto & sync = dynamic_cast(dof_manager).getSynchronizer(); if (prank == 0) { Array x_gathered(dof_manager.getSystemSize()); sync.gather(x, x_gathered); check(x_gathered); } else { sync.gather(x); } } else { check(x); } finalize(); return 0; } /* -------------------------------------------------------------------------- */ void genMesh(Mesh & mesh, UInt nb_nodes) { MeshAccessor mesh_accessor(mesh); Array & nodes = mesh_accessor.getNodes(); Array & conn = mesh_accessor.getConnectivity(_segment_2); nodes.resize(nb_nodes); for (Int n = 0; n < nb_nodes; ++n) { nodes(n, _x) = n * (1. / (nb_nodes - 1)); } conn.resize(nb_nodes - 1); for (Int n = 0; n < nb_nodes - 1; ++n) { conn(n, 0) = n; conn(n, 1) = n + 1; } mesh_accessor.makeReady(); } diff --git a/third-party/cmake/eigen3.cmake b/third-party/cmake/eigen3.cmake index a96db98ce..316700f10 100644 --- a/third-party/cmake/eigen3.cmake +++ b/third-party/cmake/eigen3.cmake @@ -1,25 +1,26 @@ set(_working_dir ${PROJECT_BINARY_DIR}/third-party/src/eigen3-download) configure_file(${PROJECT_SOURCE_DIR}/third-party/eigen3.cmake.in ${_working_dir}/CMakeLists.txt) if(NOT EXISTS ${PROJECT_SOURCE_DIR}/third-party/eigen3/CMakeLists.txt) message(STATUS "Downloading eigen3") execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result WORKING_DIRECTORY ${_working_dir} OUTPUT_FILE ${_working_dir}/configure-out.log ERROR_FILE ${_working_dir}/configure-error.log) execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY ${_working_dir} OUTPUT_FILE ${_working_dir}/build-out.log ERROR_FILE ${_working_dir}/build-error.log) endif() set(CMAKE_BUILD_TYPE Release) -set(BUILD_TESTING OFF) +set(BUILD_TESTING OFF CACHE BOOL "Eigen Tests" FORCE) add_subdirectory(${PROJECT_SOURCE_DIR}/third-party/eigen3) set(Eigen3_FOUND TRUE CACHE INTERNAL "" FORCE) set(EIGEN3_LIBRARIES eigen CACHE INTERNAL "") +mark_as_advanced(BUILD_TESTING) mask_package_options(EIGEN3) mask_package_options(EIGEN) diff --git a/third-party/eigen3.cmake.in b/third-party/eigen3.cmake.in index df824dc90..5e3e8f7ee 100644 --- a/third-party/eigen3.cmake.in +++ b/third-party/eigen3.cmake.in @@ -1,16 +1,17 @@ cmake_minimum_required(VERSION 3.1) project(eigen3-download NONE) include(ExternalProject) ExternalProject_Add(eigen3 SOURCE_DIR ${PROJECT_SOURCE_DIR}/third-party/eigen3 BINARY_DIR ${PROJECT_BINARY_DIR}/third-party/eigen3 GIT_REPOSITORY ${EIGEN3_GIT} GIT_TAG ${EIGEN3_VERSION} CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" + PATCH_COMMAND )