Page MenuHomec4science

asr_tools.cc
No OneTemporary

File Metadata

Created
Tue, May 14, 16:55

asr_tools.cc

/**
* @file ASR_tools.cc
* @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
* @author Emil Gallyamov <emil.gallyamov@epfl.ch>
*
* @brief implementation tools for the analysis of ASR samples
*
* @section LICENSE
*
* Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* Akantu is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Akantu is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Akantu. If not, see <http://www.gnu.org/licenses/>.
**/
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/property_map/property_map.hpp>
#include <fstream>
/* -------------------------------------------------------------------------- */
#include "aka_voigthelper.hh"
#include "asr_tools.hh"
#include "communicator.hh"
#include "crack_numbers_updater.hh"
#include "material_FE2.hh"
#include "material_cohesive_linear_sequential.hh"
#include "material_damage_iterative_orthotropic.hh"
#include "material_iterative_stiffness_reduction.hh"
#include "mesh_utils.hh"
#include "node_synchronizer.hh"
#include "nodes_eff_stress_updater.hh"
#include "nodes_flag_updater.hh"
#include "non_linear_solver.hh"
#include "solid_mechanics_model.hh"
#include "solid_mechanics_model_RVE.hh"
#include "solid_mechanics_model_cohesive.hh"
#include <cmath>
#include <mesh_events.hh>
/* -------------------------------------------------------------------------- */
namespace akantu {
/* -------------------------------------------------------------------------- */
ASRTools::ASRTools(SolidMechanicsModel & model)
: model(model), volume(0.), nb_dumps(0), cohesive_insertion(false),
doubled_facets_ready(false), asr_central_nodes_ready(false),
disp_stored(0, model.getSpatialDimension()),
ext_force_stored(0, model.getSpatialDimension()),
boun_stored(0, model.getSpatialDimension()),
tensile_homogenization(false), modified_pos(false),
partition_border_nodes(false), nodes_eff_stress(0), ASR_nodes(false) {
// register event handler for asr tools
auto & mesh = model.getMesh();
mesh.registerEventHandler(*this, _ehp_synchronizer);
// mesh.registerEventHandler(*this, _ehp_lowest);
if (mesh.hasMeshFacets()) {
mesh.getMeshFacets().registerEventHandler(*this, _ehp_synchronizer);
// mesh.getMeshFacets().registerEventHandler(*this, _ehp_lowest);
}
/// find four corner nodes of the RVE
findCornerNodes();
/// initialize the modified_pos array with the initial number of nodes
auto nb_nodes = mesh.getNbNodes();
modified_pos.resize(nb_nodes);
modified_pos.set(false);
partition_border_nodes.resize(nb_nodes);
partition_border_nodes.set(false);
nodes_eff_stress.resize(nb_nodes);
nodes_eff_stress.set(0);
ASR_nodes.resize(nb_nodes);
ASR_nodes.set(false);
}
/* -------------------------------------------------------------------------- */
void ASRTools::computePhaseVolumes() {
/// compute volume of each phase and save it into a map
for (auto && mat : model.getMaterials()) {
this->phase_volumes[mat.getName()] = computePhaseVolume(mat.getName());
auto it = this->phase_volumes.find(mat.getName());
if (it == this->phase_volumes.end()) {
this->phase_volumes.erase(mat.getName());
}
}
}
/* -------------------------------------------------------------------------- */
void ASRTools::computeModelVolume() {
auto const dim = model.getSpatialDimension();
auto & mesh = model.getMesh();
auto & fem = model.getFEEngine("SolidMechanicsFEEngine");
GhostType gt = _not_ghost;
this->volume = 0;
for (auto element_type : mesh.elementTypes(dim, gt, _ek_regular)) {
Array<Real> Volume(mesh.getNbElement(element_type) *
fem.getNbIntegrationPoints(element_type),
1, 1.);
this->volume += fem.integrate(Volume, element_type);
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(this->volume, SynchronizerOperation::_sum);
}
}
/* ------------------------------------------------------------------------- */
void ASRTools::applyFreeExpansionBC(Real offset) {
/// boundary conditions
const auto & mesh = model.getMesh();
const Vector<Real> & lowerBounds = mesh.getLowerBounds();
const Vector<Real> & upperBounds = mesh.getUpperBounds();
const UInt dim = mesh.getSpatialDimension();
const Array<Real> & pos = mesh.getNodes();
Array<Real> & disp = model.getDisplacement();
Array<bool> & boun = model.getBlockedDOFs();
/// accessing bounds
Real left = lowerBounds(0) + offset;
Real right = upperBounds(0) - offset;
switch (dim) {
case 2: {
Real bottom = lowerBounds(1) + offset;
Real top = upperBounds(1) - offset;
Real eps = std::abs((top - bottom) * 1e-6);
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if ((left <= pos(i, 0)) and (pos(i, 0) <= right)) {
if (std::abs(pos(i, 1) - bottom) < eps) {
boun(i, 1) = true;
disp(i, 1) = 0.0;
if (std::abs(pos(i, 0) - left) < eps) {
boun(i, 0) = true;
disp(i, 0) = 0.0;
}
}
}
}
break;
}
case 3: {
/// accessing bounds
Real bottom = lowerBounds(2) + offset;
Real top = upperBounds(2) - offset;
Real back = lowerBounds(1) + offset;
Real front = upperBounds(1) - offset;
Real eps = std::abs((top - bottom) * 1e-6);
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if ((left <= pos(i, 0)) and (pos(i, 0) <= right) and
(bottom <= pos(i, 2)) and (pos(i, 2) <= top) and
(back <= pos(i, 1)) and (pos(i, 1) <= front)) {
if (std::abs(pos(i, 2) - bottom) < eps) {
boun(i, 2) = true;
disp(i, 2) = 0.0;
}
if (std::abs(pos(i, 0) - left) < eps) {
boun(i, 0) = true;
disp(i, 0) = 0.0;
}
if (std::abs(pos(i, 1) - back) < eps) {
boun(i, 1) = true;
disp(i, 1) = 0.0;
}
}
}
break;
}
}
}
/* ------------------------------------------------------------------- */
void ASRTools::applyLoadedBC(const Vector<Real> & traction,
const ID & element_group, bool multi_axial) {
/// boundary conditions
const auto & mesh = model.getMesh();
const UInt dim = mesh.getSpatialDimension();
const Vector<Real> & lowerBounds = mesh.getLowerBounds();
const Vector<Real> & upperBounds = mesh.getUpperBounds();
Real bottom = lowerBounds(1);
Real left = lowerBounds(0);
Real top = upperBounds(1);
Real eps = std::abs((top - bottom) * 1e-6);
const Array<Real> & pos = mesh.getNodes();
Array<Real> & disp = model.getDisplacement();
Array<bool> & boun = model.getBlockedDOFs();
switch (dim) {
case 2: {
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if (std::abs(pos(i, 1) - bottom) < eps) {
boun(i, 1) = true;
disp(i, 1) = 0.0;
}
if ((std::abs(pos(i, 1) - bottom) < eps) &&
(std::abs(pos(i, 0) - left) < eps)) {
boun(i, 0) = true;
disp(i, 0) = 0.0;
}
if (multi_axial && (std::abs(pos(i, 0) - left) < eps)) {
boun(i, 0) = true;
disp(i, 0) = 0.0;
}
}
break;
}
case 3: {
Real back = lowerBounds(2);
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if ((std::abs(pos(i, 1) - bottom) < eps) &&
(std::abs(pos(i, 0) - left) < eps) &&
(std::abs(pos(i, 2) - back) < eps)) {
boun(i, 0) = true;
boun(i, 1) = true;
boun(i, 2) = true;
disp(i, 0) = 0.0;
disp(i, 1) = 0.0;
disp(i, 2) = 0.0;
}
if (std::abs(pos(i, 1) - bottom) < eps) {
boun(i, 1) = true;
disp(i, 1) = 0.0;
}
if (multi_axial && (std::abs(pos(i, 2) - back) < eps)) {
boun(i, 2) = true;
disp(i, 2) = 0.0;
}
if (multi_axial && (std::abs(pos(i, 0) - left) < eps)) {
boun(i, 0) = true;
disp(i, 0) = 0.0;
}
}
}
}
// try {
model.applyBC(BC::Neumann::FromTraction(traction), element_group);
// } catch (...) {
// }
}
/* ------------------------------------------------------------------- */
void ASRTools::applyExternalTraction(Real traction,
SpatialDirection direction) {
/// boundary conditions
auto && mesh = model.getMesh();
auto && upperBounds = mesh.getUpperBounds();
auto limit = upperBounds(direction);
auto && pos = mesh.getNodes();
auto & force = model.getExternalForce();
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if (Math::are_float_equal(pos(i, direction), limit)) {
force(i, direction) = traction;
}
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::fillNodeGroup(NodeGroup & node_group, SpatialDirection dir,
Real offset) {
const auto & mesh = model.getMesh();
const Vector<Real> & upperBounds = mesh.getUpperBounds();
const Vector<Real> & lowerBounds = mesh.getLowerBounds();
Real top = upperBounds(dir) - offset;
Real bottom = lowerBounds(dir) + offset;
Real eps = std::abs((top - bottom) * 1e-6);
const Array<Real> & pos = mesh.getNodes();
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if (std::abs(pos(i, dir) - top) < eps) {
node_group.add(i);
}
}
}
/* ------------------------------------------------------------------- */
Real ASRTools::computeAverageStrain(SpatialDirection direction, Real offset) {
Real av_displ{0};
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
const Vector<Real> & upperBounds = mesh.getUpperBounds();
const Vector<Real> & lowerBounds = mesh.getLowerBounds();
Real right = upperBounds(0) - offset;
Real left = lowerBounds(0) + offset;
Real top = upperBounds(1) - offset;
Real bottom = lowerBounds(1) + offset;
Real front;
Real back;
Real length{0};
if (dim == 3) {
front = upperBounds(2) - offset;
back = lowerBounds(2) + offset;
}
Real eps = std::abs((right - left) * 1e-6);
const Array<Real> & pos = mesh.getNodes();
const Array<Real> & disp = model.getDisplacement();
UInt nb_nodes = 0;
if (direction == _x) {
length = std::abs(right - left);
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if ((bottom <= pos(i, 1)) and (pos(i, 1) <= top) and
(std::abs(pos(i, 0) - right) < eps) and mesh.isLocalOrMasterNode(i)) {
if ((dim == 3) and (back <= pos(i, 2)) and (pos(i, 2) <= front)) {
// dirtly trick to exclude blowed up elements
if (disp(i, 0) < length / 50) {
av_displ += disp(i, 0);
++nb_nodes;
}
}
}
}
}
else if (direction == _y) {
length = std::abs(top - bottom);
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if ((left <= pos(i, 0)) and (pos(i, 0) <= right) and
(std::abs(pos(i, 1) - top) < eps) and mesh.isLocalOrMasterNode(i)) {
if ((dim == 3) and (back <= pos(i, 2)) and (pos(i, 2) <= front)) {
if (disp(i, 1) < length / 50) {
av_displ += disp(i, 1);
++nb_nodes;
}
}
}
}
} else if ((direction == _z) && (model.getSpatialDimension() == 3)) {
AKANTU_DEBUG_ASSERT(model.getSpatialDimension() == 3,
"no z-direction in 2D problem");
length = std::abs(front - back);
for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
if ((left <= pos(i, 0)) and (pos(i, 0) <= right) and
(bottom <= pos(i, 1)) and (pos(i, 1) <= top) and
(std::abs(pos(i, 2) - front) < eps) and mesh.isLocalOrMasterNode(i)) {
if (disp(i, 2) < length / 50) {
av_displ += disp(i, 2);
++nb_nodes;
}
}
}
} else {
AKANTU_EXCEPTION("The parameter for the testing direction is wrong!!!");
}
/// do not communicate if model is multi-scale
if (!aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(av_displ, SynchronizerOperation::_sum);
comm.allReduce(nb_nodes, SynchronizerOperation::_sum);
}
return av_displ / nb_nodes / length;
}
/* --------------------------------------------------------------------------
*/
Real ASRTools::computeVolumetricExpansion(SpatialDirection direction) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
UInt tensor_component = 0;
if (dim == 2) {
if (direction == _x) {
tensor_component = 0;
} else if (direction == _y) {
tensor_component = 3;
} else {
AKANTU_EXCEPTION("The parameter for the testing direction is wrong!!!");
}
}
else if (dim == 3) {
if (direction == _x) {
tensor_component = 0;
} else if (direction == _y) {
tensor_component = 4;
} else if (direction == _z) {
tensor_component = 8;
} else {
AKANTU_EXCEPTION("The parameter for the testing direction is wrong!!!");
}
} else {
AKANTU_EXCEPTION("This example does not work for 1D!!!");
}
Real gradu_tot = 0;
Real tot_volume = 0;
GhostType gt = _not_ghost;
for (auto element_type : mesh.elementTypes(dim, gt, _ek_regular)) {
const FEEngine & fe_engine = model.getFEEngine();
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
const ElementTypeMapUInt & element_filter_map =
model.getMaterial(m).getElementFilter();
if (!element_filter_map.exists(element_type, gt)) {
continue;
}
const Array<UInt> & elem_filter =
model.getMaterial(m).getElementFilter(element_type);
if (elem_filter.empty()) {
continue;
}
// const Array<Real> & gradu_vec =
// model.getMaterial(m).getGradU(element_type);
Array<Real> gradu_vec(elem_filter.size() *
fe_engine.getNbIntegrationPoints(element_type),
dim * dim, 0.);
fe_engine.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vec,
dim, element_type, gt, elem_filter);
Array<Real> int_gradu_vec(elem_filter.size(), dim * dim, "int_of_gradu");
fe_engine.integrate(gradu_vec, int_gradu_vec, dim * dim, element_type,
_not_ghost, elem_filter);
for (UInt k = 0; k < elem_filter.size(); ++k) {
gradu_tot += int_gradu_vec(k, tensor_component);
}
}
Array<Real> Volume(mesh.getNbElement(element_type) *
fe_engine.getNbIntegrationPoints(element_type),
1, 1.);
Real int_volume = fe_engine.integrate(Volume, element_type);
tot_volume += int_volume;
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(gradu_tot, SynchronizerOperation::_sum);
comm.allReduce(tot_volume, SynchronizerOperation::_sum);
}
return gradu_tot / tot_volume;
}
/* --------------------------------------------------------------------------
*/
Real ASRTools::computeDamagedVolume(const ID & mat_name) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
Real total_damage = 0;
GhostType gt = _not_ghost;
const Material & mat = model.getMaterial(mat_name);
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
const FEEngine & fe_engine = model.getFEEngine();
const ElementTypeMapUInt & element_filter_map = mat.getElementFilter();
if (!element_filter_map.exists(element_type, gt)) {
continue;
}
const Array<UInt> & elem_filter = mat.getElementFilter(element_type);
if (elem_filter.empty()) {
continue;
}
const Array<Real> & damage = mat.getInternal<Real>("damage")(element_type);
total_damage += fe_engine.integrate(damage, element_type, gt, elem_filter);
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(total_damage, SynchronizerOperation::_sum);
}
return total_damage;
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeStiffnessReduction(std::ofstream & file_output, Real time,
bool tension) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(dim != 1, "Example does not work for 1D");
/// save nodal values before test
storeNodalFields();
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
if (dim == 2) {
Real int_residual_x = 0;
Real int_residual_y = 0;
// try {
int_residual_x = performLoadingTest(_x, tension);
int_residual_y = performLoadingTest(_y, tension);
// } catch (...) {
// }
if (prank == 0) {
file_output << time << "," << int_residual_x << "," << int_residual_y
<< std::endl;
}
} else {
Real int_residual_x = performLoadingTest(_x, tension);
Real int_residual_y = performLoadingTest(_y, tension);
Real int_residual_z = performLoadingTest(_z, tension);
if (prank == 0) {
file_output << time << "," << int_residual_x << "," << int_residual_y
<< "," << int_residual_z << std::endl;
}
}
/// return the nodal values
restoreNodalFields();
}
/* -------------------------------------------------------------------------- */
void ASRTools::storeNodalFields() {
auto & disp = this->model.getDisplacement();
auto & boun = this->model.getBlockedDOFs();
auto & ext_force = this->model.getExternalForce();
this->disp_stored.copy(disp);
this->boun_stored.copy(boun);
this->ext_force_stored.copy(ext_force);
}
/* -------------------------------------------------------------------------- */
void ASRTools::restoreNodalFields() {
auto & disp = this->model.getDisplacement();
auto & boun = this->model.getBlockedDOFs();
auto & ext_force = this->model.getExternalForce();
disp.copy(this->disp_stored);
boun.copy(this->boun_stored);
ext_force.copy(this->ext_force_stored);
/// update grad_u
// model.assembleInternalForces();
}
/* ---------------------------------------------------------------------- */
void ASRTools::resetNodalFields() {
auto & disp = this->model.getDisplacement();
auto & boun = this->model.getBlockedDOFs();
auto & ext_force = this->model.getExternalForce();
disp.zero();
boun.zero();
ext_force.zero();
}
/* -------------------------------------------------------------------------- */
void ASRTools::restoreInternalFields() {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
mat.restorePreviousState();
}
}
/* -------------------------------------------------------------------------- */
void ASRTools::resetInternalFields() {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
mat.resetInternalsWithHistory();
}
}
/* -------------------------------------------------------------------------- */
void ASRTools::storeDamageField() {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
if (mat.isInternal<Real>("damage_stored", _ek_regular) &&
mat.isInternal<UInt>("reduction_step_stored", _ek_regular)) {
for (const auto & el_type : mat.getElementFilter().elementTypes(
_all_dimensions, _not_ghost, _ek_not_defined)) {
auto & red_stored =
mat.getInternal<UInt>("reduction_step_stored")(el_type, _not_ghost);
auto & red_current =
mat.getInternal<UInt>("reduction_step")(el_type, _not_ghost);
red_stored.copy(red_current);
auto & dam_stored =
mat.getInternal<Real>("damage_stored")(el_type, _not_ghost);
auto & dam_current =
mat.getInternal<Real>("damage")(el_type, _not_ghost);
dam_stored.copy(dam_current);
}
}
}
}
/* -------------------------------------------------------------------------- */
void ASRTools::restoreDamageField() {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
if (mat.isInternal<Real>("damage_stored", _ek_regular) &&
mat.isInternal<UInt>("reduction_step_stored", _ek_regular)) {
for (const auto & el_type : mat.getElementFilter().elementTypes(
_all_dimensions, _not_ghost, _ek_not_defined)) {
auto & red_stored =
mat.getInternal<UInt>("reduction_step_stored")(el_type, _not_ghost);
auto & red_current =
mat.getInternal<UInt>("reduction_step")(el_type, _not_ghost);
red_current.copy(red_stored);
auto & dam_stored =
mat.getInternal<Real>("damage_stored")(el_type, _not_ghost);
auto & dam_current =
mat.getInternal<Real>("damage")(el_type, _not_ghost);
dam_current.copy(dam_stored);
}
}
}
}
/* -------------------------------------------------------------------------- */
Real ASRTools::performLoadingTest(SpatialDirection direction, bool tension) {
UInt dir;
if (direction == _x) {
dir = 0;
}
if (direction == _y) {
dir = 1;
}
if (direction == _z) {
AKANTU_DEBUG_ASSERT(model.getSpatialDimension() == 3,
"Error in problem dimension!!!");
dir = 2;
}
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
/// indicate to material that its in the loading test
UInt nb_materials = model.getNbMaterials();
for (UInt m = 0; m < nb_materials; ++m) {
Material & mat = model.getMaterial(m);
if (aka::is_of_type<MaterialDamageIterativeOrthotropic<2>>(mat)) {
mat.setParam("loading_test", true);
}
}
/// boundary conditions
const Vector<Real> & lowerBounds = mesh.getLowerBounds();
const Vector<Real> & upperBounds = mesh.getUpperBounds();
Real bottom = lowerBounds(1);
Real top = upperBounds(1);
Real left = lowerBounds(0);
Real back;
if (dim == 3) {
back = lowerBounds(2);
}
Real eps = std::abs((top - bottom) * 1e-6);
Real imposed_displacement = std::abs(lowerBounds(dir) - upperBounds(dir));
imposed_displacement *= 0.001;
const auto & pos = mesh.getNodes();
auto & disp = model.getDisplacement();
auto & boun = model.getBlockedDOFs();
auto & ext_force = model.getExternalForce();
UInt nb_nodes = mesh.getNbNodes();
disp.zero();
boun.zero();
ext_force.zero();
if (dim == 3) {
for (UInt i = 0; i < nb_nodes; ++i) {
/// fix one corner node to avoid sliding
if ((std::abs(pos(i, 1) - bottom) < eps) &&
(std::abs(pos(i, 0) - left) < eps) &&
(std::abs(pos(i, 2) - back) < eps)) {
boun(i, 0) = true;
boun(i, 1) = true;
boun(i, 2) = true;
disp(i, 0) = 0.0;
disp(i, 1) = 0.0;
disp(i, 2) = 0.0;
}
if ((std::abs(pos(i, dir) - lowerBounds(dir)) < eps)) {
boun(i, dir) = true;
disp(i, dir) = 0.0;
}
if ((std::abs(pos(i, dir) - upperBounds(dir)) < eps)) {
boun(i, dir) = true;
disp(i, dir) = (2 * tension - 1) * imposed_displacement;
}
}
} else {
for (UInt i = 0; i < nb_nodes; ++i) {
/// fix one corner node to avoid sliding
if ((std::abs(pos(i, 1) - bottom) < eps) &&
(std::abs(pos(i, 0) - left) < eps)) {
boun(i, 0) = true;
boun(i, 1) = true;
disp(i, 0) = 0.0;
disp(i, 1) = 0.0;
}
if ((std::abs(pos(i, dir) - lowerBounds(dir)) < eps)) {
boun(i, dir) = true;
disp(i, dir) = 0.0;
}
if ((std::abs(pos(i, dir) - upperBounds(dir)) < eps)) {
boun(i, dir) = true;
disp(i, dir) = (2 * tension - 1) * imposed_displacement;
}
}
}
try {
model.solveStep();
} catch (debug::Exception & e) {
auto & solver = model.getNonLinearSolver("static");
int nb_iter = solver.get("nb_iterations");
std::cout << "Loading test did not converge in " << nb_iter
<< " iterations." << std::endl;
throw e;
}
/// compute the force (residual in this case) along the edge of the
/// imposed displacement
Real int_residual = 0.;
const Array<Real> & residual = model.getInternalForce();
for (UInt n = 0; n < nb_nodes; ++n) {
if (std::abs(pos(n, dir) - upperBounds(dir)) < eps &&
mesh.isLocalOrMasterNode(n)) {
int_residual += -residual(n, dir);
}
}
/// indicate to material that its out of the loading test
for (UInt m = 0; m < nb_materials; ++m) {
Material & mat = model.getMaterial(m);
if (aka::is_of_type<MaterialDamageIterativeOrthotropic<2>>(mat)) {
mat.setParam("loading_test", false);
}
}
/// restore historical internal fields
restoreInternalFields();
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(int_residual, SynchronizerOperation::_sum);
}
return int_residual;
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeAverageProperties(std::ofstream & file_output) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(dim != 1, "Example does not work for 1D");
Real av_tens_strain_x = computeVolumetricExpansion(_x);
Real av_tens_strain_y = computeVolumetricExpansion(_y);
Real av_lin_strain_x = computeAverageStrain(_x);
Real av_lin_strain_y = computeAverageStrain(_y);
Real damage_agg, damage_paste, crack_agg, crack_paste;
computeDamageRatioPerMaterial(damage_agg, "aggregate");
computeDamageRatioPerMaterial(damage_paste, "paste");
computeCrackVolumePerMaterial(crack_agg, "aggregate");
computeCrackVolumePerMaterial(crack_paste, "paste");
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
if (dim == 2) {
if (prank == 0)
file_output << av_tens_strain_x << "," << av_tens_strain_y << ","
<< av_lin_strain_x << "," << av_lin_strain_y << ","
<< damage_agg << "," << damage_paste << "," << crack_agg
<< "," << crack_paste << std::endl;
}
else {
Real av_lin_strain_z = computeAverageStrain(_z);
Real av_tens_strain_z = computeVolumetricExpansion(_z);
if (prank == 0)
file_output << av_tens_strain_x << "," << av_tens_strain_y << ","
<< av_tens_strain_z << "," << av_lin_strain_x << ","
<< av_lin_strain_y << "," << av_lin_strain_z << ","
<< damage_agg << "," << damage_paste << "," << crack_agg
<< "," << crack_paste << std::endl;
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeAverageProperties(std::ofstream & file_output,
Real time) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(dim != 1, "Example does not work for 1D");
Real av_tens_strain_x = computeVolumetricExpansion(_x);
Real av_tens_strain_y = computeVolumetricExpansion(_y);
Real av_lin_strain_x = computeAverageStrain(_x);
Real av_lin_strain_y = computeAverageStrain(_y);
Real damage_agg, damage_paste, crack_agg, crack_paste;
computeDamageRatioPerMaterial(damage_agg, "aggregate");
computeDamageRatioPerMaterial(damage_paste, "paste");
computeCrackVolumePerMaterial(crack_agg, "aggregate");
computeCrackVolumePerMaterial(crack_paste, "paste");
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
if (dim == 2) {
if (prank == 0)
file_output << time << "," << av_tens_strain_x << "," << av_tens_strain_y
<< "," << av_lin_strain_x << "," << av_lin_strain_y << ","
<< damage_agg << "," << damage_paste << "," << crack_agg
<< "," << crack_paste << std::endl;
}
else {
Real av_lin_strain_z = computeAverageStrain(_z);
Real av_tens_strain_z = computeVolumetricExpansion(_z);
if (prank == 0)
file_output << time << "," << av_tens_strain_x << "," << av_tens_strain_y
<< "," << av_tens_strain_z << "," << av_lin_strain_x << ","
<< av_lin_strain_y << "," << av_lin_strain_z << ","
<< damage_agg << "," << damage_paste << "," << crack_agg
<< "," << crack_paste << std::endl;
}
}
/* ----------------------------------------------------------------- */
void ASRTools::computeAveragePropertiesCohesiveModel(
std::ofstream & file_output, Real time, Real offset) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(dim != 1, "Example does not work for 1D");
Real av_strain_x = computeAverageStrain(_x, offset);
Real av_strain_y = computeAverageStrain(_y, offset);
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
if (dim == 2) {
if (prank == 0)
file_output << time << "," << av_strain_x << "," << av_strain_y << ","
<< std::endl;
}
else {
Real av_strain_z = computeAverageStrain(_z, offset);
if (prank == 0)
file_output << time << "," << av_strain_x << "," << av_strain_y << ","
<< av_strain_z << std::endl;
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeAveragePropertiesFe2Material(std::ofstream & file_output,
Real time) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(dim != 1, "Example does not work for 1D");
Real av_tens_strain_x = computeVolumetricExpansion(_x);
Real av_tens_strain_y = computeVolumetricExpansion(_y);
Real av_lin_strain_x = computeAverageStrain(_x);
Real av_lin_strain_y = computeAverageStrain(_y);
Real crack_agg = averageScalarField("crack_volume_ratio_agg");
Real crack_paste = averageScalarField("crack_volume_ratio_paste");
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
if (dim == 2) {
if (prank == 0)
file_output << time << "," << av_tens_strain_x << "," << av_tens_strain_y
<< "," << av_lin_strain_x << "," << av_lin_strain_y << ","
<< crack_agg << "," << crack_paste << std::endl;
}
else {
Real av_lin_strain_z = computeAverageStrain(_z);
Real av_tens_strain_z = computeVolumetricExpansion(_z);
if (prank == 0)
file_output << time << "," << av_tens_strain_x << "," << av_tens_strain_y
<< "," << av_tens_strain_z << "," << av_lin_strain_x << ","
<< av_lin_strain_y << "," << av_lin_strain_z << ","
<< crack_agg << "," << crack_paste << std::endl;
}
}
/* ------------------------------------------------------------------- */
void ASRTools::saveState(UInt current_step) {
/// variables for parallel execution
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
GhostType gt = _not_ghost;
/// save the reduction step on each quad
UInt nb_materials = model.getNbMaterials();
/// open the output file
std::stringstream file_stream;
file_stream << "./restart/reduction_steps_file_" << prank << "_"
<< current_step << ".txt";
std::string reduction_steps_file = file_stream.str();
std::ofstream file_output;
file_output.open(reduction_steps_file.c_str());
if (!file_output.is_open())
AKANTU_EXCEPTION("Could not create the file " + reduction_steps_file +
", does its folder exist?");
for (UInt m = 0; m < nb_materials; ++m) {
const Material & mat = model.getMaterial(m);
if (mat.getName() == "gel")
continue;
/// get the reduction steps internal field
const InternalField<UInt> & reduction_steps =
mat.getInternal<UInt>("damage_step");
/// loop over all types in that material
for (auto element_type : reduction_steps.elementTypes(gt)) {
const Array<UInt> & elem_filter = mat.getElementFilter(element_type, gt);
if (!elem_filter.size())
continue;
const Array<UInt> & reduction_step_array =
reduction_steps(element_type, gt);
for (UInt i = 0; i < reduction_step_array.size(); ++i) {
file_output << reduction_step_array(i) << std::endl;
if (file_output.fail())
AKANTU_EXCEPTION("Error in writing data to file " +
reduction_steps_file);
}
}
}
/// close the file
file_output.close();
comm.barrier();
/// write the number of the last successfully saved step in a file
if (prank == 0) {
std::string current_step_file = "./restart/current_step.txt";
std::ofstream file_output;
file_output.open(current_step_file.c_str());
file_output << current_step << std::endl;
if (file_output.fail())
AKANTU_EXCEPTION("Error in writing data to file " + current_step_file);
file_output.close();
}
}
/* ------------------------------------------------------------------ */
bool ASRTools::loadState(UInt & current_step) {
current_step = 0;
bool restart = false;
/// variables for parallel execution
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
GhostType gt = _not_ghost;
/// proc 0 has to save the current step
if (prank == 0) {
std::string line;
std::string current_step_file = "./restart/current_step.txt";
std::ifstream file_input;
file_input.open(current_step_file.c_str());
if (file_input.is_open()) {
std::getline(file_input, line);
std::stringstream sstr(line);
sstr >> current_step;
file_input.close();
}
}
comm.broadcast(current_step);
if (!current_step)
return restart;
if (prank == 0)
std::cout << "....Restarting simulation" << std::endl;
restart = true;
/// save the reduction step on each quad
UInt nb_materials = model.getNbMaterials();
/// open the output file
std::stringstream file_stream;
file_stream << "./restart/reduction_steps_file_" << prank << "_"
<< current_step << ".txt";
std::string reduction_steps_file = file_stream.str();
std::ifstream file_input;
file_input.open(reduction_steps_file.c_str());
if (!file_input.is_open())
AKANTU_EXCEPTION("Could not open file " + reduction_steps_file);
for (UInt m = 0; m < nb_materials; ++m) {
const Material & mat = model.getMaterial(m);
if (mat.getName() == "gel")
continue;
/// get the material parameters
Real E = mat.getParam("E");
Real max_damage = mat.getParam("max_damage");
Real max_reductions = mat.getParam("max_reductions");
/// get the internal field that need to be set
InternalField<UInt> & reduction_steps =
const_cast<InternalField<UInt> &>(mat.getInternal<UInt>("damage_step"));
InternalField<Real> & Sc =
const_cast<InternalField<Real> &>(mat.getInternal<Real>("Sc"));
InternalField<Real> & damage =
const_cast<InternalField<Real> &>(mat.getInternal<Real>("damage"));
/// loop over all types in that material
Real reduction_constant = mat.getParam("reduction_constant");
for (auto element_type : reduction_steps.elementTypes(gt)) {
const Array<UInt> & elem_filter = mat.getElementFilter(element_type, gt);
if (!elem_filter.size())
continue;
Array<UInt> & reduction_step_array = reduction_steps(element_type, gt);
Array<Real> & Sc_array = Sc(element_type, gt);
Array<Real> & damage_array = damage(element_type, gt);
const Array<Real> & D_tangent =
mat.getInternal<Real>("tangent")(element_type, gt);
const Array<Real> & eps_u =
mat.getInternal<Real>("ultimate_strain")(element_type, gt);
std::string line;
for (UInt i = 0; i < reduction_step_array.size(); ++i) {
std::getline(file_input, line);
if (file_input.fail())
AKANTU_EXCEPTION("Could not read data from file " +
reduction_steps_file);
std::stringstream sstr(line);
sstr >> reduction_step_array(i);
if (reduction_step_array(i) == 0)
continue;
if (reduction_step_array(i) == max_reductions) {
damage_array(i) = max_damage;
Real previous_damage =
1. -
(1. / std::pow(reduction_constant, reduction_step_array(i) - 1));
Sc_array(i) = eps_u(i) * (1. - previous_damage) * E * D_tangent(i) /
((1. - previous_damage) * E + D_tangent(i));
} else {
damage_array(i) =
1. - (1. / std::pow(reduction_constant, reduction_step_array(i)));
Sc_array(i) = eps_u(i) * (1. - damage_array(i)) * E * D_tangent(i) /
((1. - damage_array(i)) * E + D_tangent(i));
}
}
}
}
/// close the file
file_input.close();
return restart;
}
/* ------------------------------------------------------------------- */
Real ASRTools::computePhaseVolume(const ID & mat_name) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
Real total_volume = 0;
GhostType gt = _not_ghost;
const Material & mat = model.getMaterial(mat_name);
for (auto element_type : mesh.elementTypes(dim, gt, _ek_regular)) {
const FEEngine & fe_engine = model.getFEEngine();
const ElementTypeMapUInt & element_filter_map = mat.getElementFilter();
if (!element_filter_map.exists(element_type, gt))
continue;
const Array<UInt> & elem_filter = mat.getElementFilter(element_type);
if (!elem_filter.size())
continue;
Array<Real> volume(elem_filter.size() *
fe_engine.getNbIntegrationPoints(element_type),
1, 1.);
total_volume += fe_engine.integrate(volume, element_type, gt, elem_filter);
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(total_volume, SynchronizerOperation::_sum);
}
return total_volume;
}
/* --------------------------------------------------------------------------
*/
void ASRTools::applyEigenGradUinCracks(
const Matrix<Real> prescribed_eigen_grad_u, const ID & material_name) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
Material & mat = model.getMaterial(material_name);
const Real max_damage = mat.getParam("max_damage");
const ElementTypeMapUInt & element_filter = mat.getElementFilter();
for (auto element_type :
element_filter.elementTypes(dim, gt, _ek_not_defined)) {
if (!element_filter(element_type, gt).size())
continue;
const Array<Real> & damage =
mat.getInternal<Real>("damage")(element_type, gt);
const Real * dam_it = damage.storage();
Array<Real> & eigen_gradu =
mat.getInternal<Real>("eigen_grad_u")(element_type, gt);
Array<Real>::matrix_iterator eigen_it = eigen_gradu.begin(dim, dim);
Array<Real>::matrix_iterator eigen_end = eigen_gradu.end(dim, dim);
for (; eigen_it != eigen_end; ++eigen_it, ++dam_it) {
if (Math::are_float_equal(max_damage, *dam_it)) {
Matrix<Real> & current_eigengradu = *eigen_it;
current_eigengradu = prescribed_eigen_grad_u;
}
}
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::applyEigenGradUinCracks(
const Matrix<Real> prescribed_eigen_grad_u,
const ElementTypeMapUInt & critical_elements, bool to_add) {
GhostType gt = _not_ghost;
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
const Array<UInt> & critical_elements_vec =
critical_elements(element_type, gt);
const Array<UInt> & material_index_vec =
model.getMaterialByElement(element_type, gt);
const Array<UInt> & material_local_numbering_vec =
model.getMaterialLocalNumbering(element_type, gt);
for (UInt e = 0; e < critical_elements_vec.size(); ++e) {
UInt element = critical_elements_vec(e);
Material & material = model.getMaterial(material_index_vec(element));
Array<Real> & eigen_gradu =
material.getInternal<Real>("eigen_grad_u")(element_type, gt);
UInt material_local_num = material_local_numbering_vec(element);
Array<Real>::matrix_iterator eigen_it = eigen_gradu.begin(dim, dim);
eigen_it += material_local_num;
Matrix<Real> & current_eigengradu = *eigen_it;
if (to_add)
current_eigengradu += prescribed_eigen_grad_u;
else
current_eigengradu = prescribed_eigen_grad_u;
}
}
}
// /*
// --------------------------------------------------------------------------
// */ void ASRTools<dim>::fillCracks(ElementTypeMapReal & saved_damage) {
// const UInt dim = model.getSpatialDimension();
// const Material & mat_gel = model.getMaterial("gel");
// const Real E_gel = mat_gel.getParam("E");
// Real E_homogenized = 0.;
// GhostType gt = _not_ghost;
// const auto & mesh = model.getMesh();
// for (UInt m = 0; m < model.getNbMaterials(); ++m) {
// Material & mat = model.getMaterial(m);
// if (mat.getName() == "gel")
// continue;
// const Real E = mat.getParam("E");
// InternalField<Real> & damage = mat.getInternal<Real>("damage");
// for (auto element_type : mesh.elementTypes(dim, gt, _ek_regular)) {
// const Array<UInt> & elem_filter =
// mat.getElementFilter(element_type, gt); if (!elem_filter.size())
// continue;
// Array<Real> & damage_vec = damage(element_type, gt);
// Array<Real> & saved_damage_vec = saved_damage(element_type, gt);
// for (UInt i = 0; i < damage_vec.size(); ++i) {
// saved_damage_vec(elem_filter(i)) = damage_vec(i);
// E_homogenized = (E_gel - E) * damage_vec(i) + E;
// damage_vec(i) = 1. - (E_homogenized / E);
// }
// }
// }
// }
// /*
// --------------------------------------------------------------------------
// */ void ASRTools<dim>::drainCracks(const ElementTypeMapReal &
// saved_damage) {
// // model.dump();
// const UInt dim = model.getSpatialDimension();
// const auto & mesh = model.getMesh();
// GhostType gt = _not_ghost;
// for (UInt m = 0; m < model.getNbMaterials(); ++m) {
// Material & mat = model.getMaterial(m);
// if (mat.getName() == "gel")
// continue;
// else {
// InternalField<Real> & damage = mat.getInternal<Real>("damage");
// for (auto element_type : mesh.elementTypes(dim, gt,
// _ek_not_defined)) {
// const Array<UInt> & elem_filter =
// mat.getElementFilter(element_type, gt);
// if (!elem_filter.size())
// continue;
// Array<Real> & damage_vec = damage(element_type, gt);
// const Array<Real> & saved_damage_vec =
// saved_damage(element_type, gt); for (UInt i = 0; i <
// damage_vec.size(); ++i) {
// damage_vec(i) = saved_damage_vec(elem_filter(i));
// }
// }
// }
// }
// // model.dump();
// }
/* --------------------------------------------------------------------------
*/
Real ASRTools::computeSmallestElementSize() {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
// constexpr auto dim = model.getSpatialDimension();
/// compute smallest element size
const Array<Real> & pos = mesh.getNodes();
Real el_h_min = std::numeric_limits<Real>::max();
GhostType gt = _not_ghost;
for (auto element_type : mesh.elementTypes(dim, gt)) {
UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type);
UInt nb_element = mesh.getNbElement(element_type);
Array<Real> X(0, nb_nodes_per_element * dim);
model.getFEEngine().extractNodalToElementField(mesh, pos, X, element_type,
_not_ghost);
Array<Real>::matrix_iterator X_el = X.begin(dim, nb_nodes_per_element);
for (UInt el = 0; el < nb_element; ++el, ++X_el) {
Real el_h = model.getFEEngine().getElementInradius(*X_el, element_type);
if (el_h < el_h_min)
el_h_min = el_h;
}
}
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(el_h_min, SynchronizerOperation::_min);
}
return el_h_min;
}
// /*
// --------------------------------------------------------------------------
// */
// /// apply homogeneous temperature on the whole specimen
// void ASRTools<dim>::applyTemperatureFieldToSolidmechanicsModel(
// const Real & temperature) {
// UInt dim = model.getMesh().getSpatialDimension();
// for (UInt m = 0; m < model.getNbMaterials(); ++m) {
// Material & mat = model.getMaterial(m);
// for (auto el_type : mat.getElementFilter().elementTypes(dim)) {
// const auto & filter = mat.getElementFilter()(el_type);
// if (filter.size() == 0)
// continue;
// auto & delta_T = mat.getArray<Real>("delta_T", el_type);
// auto dt = delta_T.begin();
// auto dt_end = delta_T.end();
// for (; dt != dt_end; ++dt) {
// *dt = temperature;
// }
// }
// }
// }
/* ----------------------------------------------------------------------- */
void ASRTools::computeASRStrainLarive(
const Real & delta_time_day, const Real & T, Real & ASRStrain,
const Real & eps_inf, const Real & time_ch_ref, const Real & time_lat_ref,
const Real & U_C, const Real & U_L, const Real & T_ref) {
AKANTU_DEBUG_IN();
Real time_ch, time_lat, lambda, ksi, exp_ref;
ksi = ASRStrain / eps_inf;
if (T == 0) {
ksi += 0;
} else {
time_ch = time_ch_ref * std::exp(U_C * (1. / T - 1. / T_ref));
time_lat = time_lat_ref * std::exp(U_L * (1. / T - 1. / T_ref));
exp_ref = std::exp(-time_lat / time_ch);
lambda = (1 + exp_ref) / (ksi + exp_ref);
ksi += delta_time_day / time_ch * (1 - ksi) / lambda;
}
ASRStrain = ksi * eps_inf;
AKANTU_DEBUG_OUT();
}
/* ----------------------------------------------------------------------- */
void ASRTools::computeASRStrainArrhenius(const Real & delta_time_day,
const Real & T, Real & ASRStrain,
const Real & k, const Real & Ea) {
AKANTU_DEBUG_IN();
if (T != 0) {
const Real R = 8.3145; // J / mol / K
ASRStrain += delta_time_day * k * std::exp(-Ea / R / T);
}
AKANTU_DEBUG_OUT();
}
/* ----------------------------------------------------------------------- */
Real ASRTools::computeDeltaGelStrainThermal(const Real delta_time_day,
const Real k,
const Real activ_energy,
const Real R, const Real T,
Real & amount_reactive_particles,
const Real saturation_const) {
/// compute increase in gel strain value for interval of time delta_time
/// as temperatures are stored in C, conversion to K is done
Real delta_strain = amount_reactive_particles * k *
std::exp(-activ_energy / (R * T)) * delta_time_day;
amount_reactive_particles -=
std::exp(-activ_energy / (R * T)) * delta_time_day / saturation_const;
if (amount_reactive_particles < 0.)
amount_reactive_particles = 0.;
return delta_strain;
}
/* -----------------------------------------------------------------------*/
Real ASRTools::computeDeltaGelStrainLinear(const Real delta_time,
const Real k) {
/// compute increase in gel strain value for dt simply by deps = k *
/// delta_time
Real delta_strain = k * delta_time;
return delta_strain;
}
/* ---------------------------------------------------------------------- */
void ASRTools::applyBoundaryConditionsRve(
const Matrix<Real> & displacement_gradient) {
AKANTU_DEBUG_IN();
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
// /// transform into Green strain to exclude rotations
// auto F = displacement_gradient + Matrix<Real>::eye(dim);
// auto E = 0.5 * (F.transpose() * F - Matrix<Real>::eye(dim));
/// get the position of the nodes
const Array<Real> & pos = mesh.getNodes();
/// storage for the coordinates of a given node and the displacement
/// that will be applied
Vector<Real> x(dim);
Vector<Real> appl_disp(dim);
const auto & lower_bounds = mesh.getLowerBounds();
for (auto node : this->corner_nodes) {
x(0) = pos(node, 0);
x(1) = pos(node, 1);
x -= lower_bounds;
appl_disp.mul<false>(displacement_gradient, x);
(model.getBlockedDOFs())(node, 0) = true;
(model.getDisplacement())(node, 0) = appl_disp(0);
(model.getBlockedDOFs())(node, 1) = true;
(model.getDisplacement())(node, 1) = appl_disp(1);
}
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
void ASRTools::applyHomogeneousTemperature(const Real & temperature) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
for (auto el_type : mat.getElementFilter().elementTypes(dim)) {
const auto & filter = mat.getElementFilter()(el_type);
if (filter.size() == 0)
continue;
auto & deltas_T = mat.getArray<Real>("delta_T", el_type);
for (auto && delta_T : deltas_T) {
delta_T = temperature;
}
}
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::removeTemperature() {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
for (auto el_type : mat.getElementFilter().elementTypes(dim)) {
const auto & filter = mat.getElementFilter()(el_type);
if (filter.size() == 0)
continue;
auto & deltas_T = mat.getArray<Real>("delta_T", el_type);
for (auto && delta_T : deltas_T) {
delta_T = 0.;
}
}
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::findCornerNodes() {
AKANTU_DEBUG_IN();
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
// find corner nodes
const auto & position = mesh.getNodes();
const auto & lower_bounds = mesh.getLowerBounds();
const auto & upper_bounds = mesh.getUpperBounds();
switch (dim) {
case 2: {
corner_nodes.resize(4);
corner_nodes.set(UInt(-1));
for (auto && data : enumerate(make_view(position, dim))) {
auto node = std::get<0>(data);
const auto & X = std::get<1>(data);
auto distance = X.distance(lower_bounds);
// node 1 - left bottom corner
if (Math::are_float_equal(distance, 0)) {
corner_nodes(0) = node;
}
// node 2 - right bottom corner
else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
Math::are_float_equal(X(_y), lower_bounds(_y))) {
corner_nodes(1) = node;
}
// node 3 - right top
else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
Math::are_float_equal(X(_y), upper_bounds(_y))) {
corner_nodes(2) = node;
}
// node 4 - left top
else if (Math::are_float_equal(X(_x), lower_bounds(_x)) &&
Math::are_float_equal(X(_y), upper_bounds(_y))) {
corner_nodes(3) = node;
}
}
break;
}
case 3: {
corner_nodes.resize(8);
corner_nodes.set(UInt(-1));
for (auto && data : enumerate(make_view(position, dim))) {
auto node = std::get<0>(data);
const auto & X = std::get<1>(data);
auto distance = X.distance(lower_bounds);
// node 1
if (Math::are_float_equal(distance, 0)) {
corner_nodes(0) = node;
}
// node 2
else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
Math::are_float_equal(X(_y), lower_bounds(_y)) &&
Math::are_float_equal(X(_z), lower_bounds(_z))) {
corner_nodes(1) = node;
}
// node 3
else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
Math::are_float_equal(X(_y), upper_bounds(_y)) &&
Math::are_float_equal(X(_z), lower_bounds(_z))) {
corner_nodes(2) = node;
}
// node 4
else if (Math::are_float_equal(X(_x), lower_bounds(_x)) &&
Math::are_float_equal(X(_y), upper_bounds(_y)) &&
Math::are_float_equal(X(_z), lower_bounds(_z))) {
corner_nodes(3) = node;
}
// node 5
if (Math::are_float_equal(X(_x), lower_bounds(_x)) &&
Math::are_float_equal(X(_y), lower_bounds(_y)) &&
Math::are_float_equal(X(_z), upper_bounds(_z))) {
corner_nodes(4) = node;
}
// node 6
else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
Math::are_float_equal(X(_y), lower_bounds(_y)) &&
Math::are_float_equal(X(_z), upper_bounds(_z))) {
corner_nodes(5) = node;
}
// node 7
else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
Math::are_float_equal(X(_y), upper_bounds(_y)) &&
Math::are_float_equal(X(_z), upper_bounds(_z))) {
corner_nodes(6) = node;
}
// node 8
else if (Math::are_float_equal(X(_x), lower_bounds(_x)) &&
Math::are_float_equal(X(_y), upper_bounds(_y)) &&
Math::are_float_equal(X(_z), upper_bounds(_z))) {
corner_nodes(7) = node;
}
}
break;
}
}
// AKANTU_DEBUG_ASSERT(dim == 2, "This is 2D only!");
// for (UInt i = 0; i < corner_nodes.size(); ++i) {
// if (corner_nodes(i) == UInt(-1))
// AKANTU_ERROR("The corner node " << i + 1 << " wasn't found");
// }
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
Real ASRTools::averageScalarField(const ID & field_name) {
AKANTU_DEBUG_IN();
auto & fem = model.getFEEngine("SolidMechanicsFEEngine");
Real average = 0;
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
const auto & elem_filter =
model.getMaterial(m).getElementFilter(element_type);
if (!elem_filter.size())
continue;
const auto & scalar_field =
model.getMaterial(m).getInternal<Real>(field_name)(element_type);
Array<Real> int_scalar_vec(elem_filter.size(), 1, "int_of_scalar");
fem.integrate(scalar_field, int_scalar_vec, 1, element_type, _not_ghost,
elem_filter);
for (UInt k = 0; k < elem_filter.size(); ++k)
average += int_scalar_vec(k);
}
}
/// compute total model volume
if (!this->volume)
computeModelVolume();
return average / this->volume;
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
Real ASRTools::averageTensorField(UInt row_index, UInt col_index,
const ID & field_type) {
AKANTU_DEBUG_IN();
auto & fem = model.getFEEngine("SolidMechanicsFEEngine");
Real average = 0;
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
if (field_type == "stress") {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
const auto & stress_vec = model.getMaterial(m).getStress(element_type);
const auto & elem_filter =
model.getMaterial(m).getElementFilter(element_type);
Array<Real> int_stress_vec(elem_filter.size(), dim * dim,
"int_of_stress");
fem.integrate(stress_vec, int_stress_vec, dim * dim, element_type,
_not_ghost, elem_filter);
for (UInt k = 0; k < elem_filter.size(); ++k)
average +=
int_stress_vec(k, row_index * dim + col_index); // 3 is the value
// for the yy (in
// 3D, the value
// is 4)
}
} else if (field_type == "strain") {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
const auto & gradu_vec = model.getMaterial(m).getGradU(element_type);
const auto & elem_filter =
model.getMaterial(m).getElementFilter(element_type);
Array<Real> int_gradu_vec(elem_filter.size(), dim * dim,
"int_of_gradu");
fem.integrate(gradu_vec, int_gradu_vec, dim * dim, element_type,
_not_ghost, elem_filter);
for (UInt k = 0; k < elem_filter.size(); ++k)
/// averaging is done only for normal components, so stress and
/// strain are equal
average += 0.5 * (int_gradu_vec(k, row_index * dim + col_index) +
int_gradu_vec(k, col_index * dim + row_index));
}
} else if (field_type == "eigen_grad_u") {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
const auto & eigen_gradu_vec = model.getMaterial(m).getInternal<Real>(
"eigen_grad_u")(element_type);
const auto & elem_filter =
model.getMaterial(m).getElementFilter(element_type);
Array<Real> int_eigen_gradu_vec(elem_filter.size(), dim * dim,
"int_of_gradu");
fem.integrate(eigen_gradu_vec, int_eigen_gradu_vec, dim * dim,
element_type, _not_ghost, elem_filter);
for (UInt k = 0; k < elem_filter.size(); ++k)
/// averaging is done only for normal components, so stress and
/// strain are equal
average += int_eigen_gradu_vec(k, row_index * dim + col_index);
}
} else {
AKANTU_ERROR("Averaging not implemented for this field!!!");
}
}
/// compute total model volume
if (!this->volume)
computeModelVolume();
return average / this->volume;
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
void ASRTools::homogenizeStressField(Matrix<Real> & stress) {
AKANTU_DEBUG_IN();
stress(0, 0) = averageTensorField(0, 0, "stress");
stress(1, 1) = averageTensorField(1, 1, "stress");
stress(0, 1) = averageTensorField(0, 1, "stress");
stress(1, 0) = averageTensorField(1, 0, "stress");
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
void ASRTools::setStiffHomogenDir(Matrix<Real> & stress) {
AKANTU_DEBUG_IN();
auto dim = stress.rows();
Vector<Real> eigenvalues(dim);
stress.eig(eigenvalues);
Real hydrostatic_stress = 0;
UInt denominator = 0;
for (UInt i = 0; i < dim; ++i, ++denominator)
hydrostatic_stress += eigenvalues(i);
hydrostatic_stress /= denominator;
AKANTU_DEBUG_OUT();
this->tensile_homogenization = (hydrostatic_stress > 0);
}
/* --------------------------------------------------------------------------
*/
void ASRTools::homogenizeStiffness(Matrix<Real> & C_macro, bool tensile_test) {
AKANTU_DEBUG_IN();
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(dim == 2, "Is only implemented for 2D!!!");
/// apply three independent loading states to determine C
/// 1. eps_el = (0.001;0;0) 2. eps_el = (0,0.001,0) 3. eps_el = (0,0,0.001)
/// store and clear the eigenstrain
///(to exclude stresses due to internal pressure)
Array<Real> stored_eig(0, dim * dim, 0);
storeASREigenStrain(stored_eig);
clearASREigenStrain();
/// save nodal values before tests
storeNodalFields();
/// storage for results of 3 different loading states
UInt voigt_size = 1;
switch (dim) {
case 2: {
voigt_size = VoigtHelper<2>::size;
break;
}
case 3: {
voigt_size = VoigtHelper<3>::size;
break;
}
}
Matrix<Real> stresses(voigt_size, voigt_size, 0.);
Matrix<Real> strains(voigt_size, voigt_size, 0.);
Matrix<Real> H(dim, dim, 0.);
/// save the damage state before filling up cracks
// ElementTypeMapReal saved_damage("saved_damage");
// saved_damage.initialize(getFEEngine(), _nb_component = 1,
// _default_value = 0); this->fillCracks(saved_damage);
/// indicate to material that its in the loading test
UInt nb_materials = model.getNbMaterials();
for (UInt m = 0; m < nb_materials; ++m) {
Material & mat = model.getMaterial(m);
if (aka::is_of_type<MaterialDamageIterativeOrthotropic<2>>(mat)) {
mat.setParam("loading_test", true);
}
}
/// virtual test 1:
H(0, 0) = 0.001 * (2 * tensile_test - 1);
performVirtualTesting(H, stresses, strains, 0);
/// virtual test 2:
H.zero();
H(1, 1) = 0.001 * (2 * tensile_test - 1);
performVirtualTesting(H, stresses, strains, 1);
/// virtual test 3:
H.zero();
H(0, 1) = 0.001;
H(1, 0) = 0.001;
performVirtualTesting(H, stresses, strains, 2);
/// indicate to material that its out of the loading test
for (UInt m = 0; m < nb_materials; ++m) {
Material & mat = model.getMaterial(m);
if (aka::is_of_type<MaterialDamageIterativeOrthotropic<2>>(mat)) {
mat.setParam("loading_test", false);
}
}
/// drain cracks
// this->drainCracks(saved_damage);
/// compute effective stiffness
Matrix<Real> eps_inverse(voigt_size, voigt_size);
eps_inverse.inverse(strains);
/// Make C matrix symmetric
Matrix<Real> C_direct(voigt_size, voigt_size);
C_direct.mul<false, false>(stresses, eps_inverse);
for (UInt i = 0; i != voigt_size; ++i) {
for (UInt j = 0; j != voigt_size; ++j) {
C_macro(i, j) = 0.5 * (C_direct(i, j) + C_direct(j, i));
C_macro(j, i) = C_macro(i, j);
}
}
/// return the nodal values and the ASR eigenstrain
restoreNodalFields();
restoreASREigenStrain(stored_eig);
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
void ASRTools::performVirtualTesting(const Matrix<Real> & H,
Matrix<Real> & eff_stresses,
Matrix<Real> & eff_strains,
const UInt test_no) {
AKANTU_DEBUG_IN();
auto & disp = model.getDisplacement();
auto & boun = model.getBlockedDOFs();
auto & ext_force = model.getExternalForce();
disp.zero();
boun.zero();
ext_force.zero();
applyBoundaryConditionsRve(H);
model.solveStep();
/// get average stress and strain
eff_stresses(0, test_no) = averageTensorField(0, 0, "stress");
eff_strains(0, test_no) = averageTensorField(0, 0, "strain");
eff_stresses(1, test_no) = averageTensorField(1, 1, "stress");
eff_strains(1, test_no) = averageTensorField(1, 1, "strain");
eff_stresses(2, test_no) = averageTensorField(1, 0, "stress");
eff_strains(2, test_no) = 2. * averageTensorField(1, 0, "strain");
/// restore historical internal fields
restoreInternalFields();
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------- */
void ASRTools::homogenizeEigenGradU(Matrix<Real> & eigen_gradu_macro) {
AKANTU_DEBUG_IN();
eigen_gradu_macro(0, 0) = averageTensorField(0, 0, "eigen_grad_u");
eigen_gradu_macro(1, 1) = averageTensorField(1, 1, "eigen_grad_u");
eigen_gradu_macro(0, 1) = averageTensorField(0, 1, "eigen_grad_u");
eigen_gradu_macro(1, 0) = averageTensorField(1, 0, "eigen_grad_u");
AKANTU_DEBUG_OUT();
}
/* -------------------------------------------------------------------------
*/
void ASRTools::fillCracks(ElementTypeMapReal & saved_damage) {
const auto & mat_gel = model.getMaterial("gel");
Real E_gel = mat_gel.get("E");
Real E_homogenized = 0.;
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
if (mat.getName() == "gel" || mat.getName() == "FE2_mat")
continue;
Real E = mat.get("E");
auto & damage = mat.getInternal<Real>("damage");
GhostType gt = _not_ghost;
for (auto && type : damage.elementTypes(gt)) {
const auto & elem_filter = mat.getElementFilter(type);
auto nb_integration_point =
model.getFEEngine().getNbIntegrationPoints(type);
auto sav_dam_it =
make_view(saved_damage(type), nb_integration_point).begin();
for (auto && data :
zip(elem_filter, make_view(damage(type), nb_integration_point))) {
auto el = std::get<0>(data);
auto & dam = std::get<1>(data);
Vector<Real> sav_dam = sav_dam_it[el];
sav_dam = dam;
for (auto q : arange(dam.size())) {
E_homogenized = (E_gel - E) * dam(q) + E;
dam(q) = 1. - (E_homogenized / E);
}
}
}
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::drainCracks(const ElementTypeMapReal & saved_damage) {
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
if (mat.getName() == "gel" || mat.getName() == "FE2_mat")
continue;
auto & damage = mat.getInternal<Real>("damage");
GhostType gt = _not_ghost;
for (auto && type : damage.elementTypes(gt)) {
const auto & elem_filter = mat.getElementFilter(type);
auto nb_integration_point =
model.getFEEngine().getNbIntegrationPoints(type);
auto sav_dam_it =
make_view(saved_damage(type), nb_integration_point).begin();
for (auto && data :
zip(elem_filter, make_view(damage(type), nb_integration_point))) {
auto el = std::get<0>(data);
auto & dam = std::get<1>(data);
Vector<Real> sav_dam = sav_dam_it[el];
dam = sav_dam;
}
}
}
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeDamageRatio(Real & damage_ratio) {
damage_ratio = 0.;
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
if (mat.getName() == "gel" || mat.getName() == "FE2_mat")
continue;
GhostType gt = _not_ghost;
const ElementTypeMapArray<UInt> & filter_map = mat.getElementFilter();
// Loop over the boundary element types
for (auto & element_type : filter_map.elementTypes(dim, gt)) {
const Array<UInt> & filter = filter_map(element_type);
if (!filter_map.exists(element_type, gt))
continue;
if (filter.size() == 0)
continue;
const FEEngine & fe_engine = model.getFEEngine();
auto & damage_array = mat.getInternal<Real>("damage")(element_type);
damage_ratio +=
fe_engine.integrate(damage_array, element_type, gt, filter);
}
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(damage_ratio, SynchronizerOperation::_sum);
}
/// compute total model volume
if (!this->volume)
computeModelVolume();
damage_ratio /= this->volume;
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeDamageRatioPerMaterial(Real & damage_ratio,
const ID & material_name) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
Material & mat = model.getMaterial(material_name);
const ElementTypeMapArray<UInt> & filter_map = mat.getElementFilter();
const FEEngine & fe_engine = model.getFEEngine();
damage_ratio = 0.;
// Loop over the boundary element types
for (auto & element_type : filter_map.elementTypes(dim, gt)) {
const Array<UInt> & filter = filter_map(element_type);
if (!filter_map.exists(element_type, gt))
continue;
if (filter.size() == 0)
continue;
auto & damage_array = mat.getInternal<Real>("damage")(element_type);
damage_ratio += fe_engine.integrate(damage_array, element_type, gt, filter);
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(damage_ratio, SynchronizerOperation::_sum);
}
if (not this->phase_volumes.size())
computePhaseVolumes();
damage_ratio /= this->phase_volumes[material_name];
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeCrackVolume(Real & crack_volume_ratio) {
crack_volume_ratio = 0.;
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
for (UInt m = 0; m < model.getNbMaterials(); ++m) {
Material & mat = model.getMaterial(m);
if (mat.getName() == "gel" || mat.getName() == "FE2_mat")
continue;
GhostType gt = _not_ghost;
const ElementTypeMapArray<UInt> & filter_map = mat.getElementFilter();
// Loop over the boundary element types
for (auto & element_type : filter_map.elementTypes(dim, gt)) {
const Array<UInt> & filter = filter_map(element_type);
if (!filter_map.exists(element_type, gt))
continue;
if (filter.size() == 0)
continue;
auto extra_volume_copy =
mat.getInternal<Real>("extra_volume")(element_type);
crack_volume_ratio += Math::reduce(extra_volume_copy);
}
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(crack_volume_ratio, SynchronizerOperation::_sum);
}
/// compute total model volume
if (!this->volume)
computeModelVolume();
crack_volume_ratio /= this->volume;
}
/* --------------------------------------------------------------------------
*/
void ASRTools::computeCrackVolumePerMaterial(Real & crack_volume,
const ID & material_name) {
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
Material & mat = model.getMaterial(material_name);
const ElementTypeMapArray<UInt> & filter_map = mat.getElementFilter();
crack_volume = 0.;
// Loop over the boundary element types
for (auto & element_type : filter_map.elementTypes(dim, gt)) {
const Array<UInt> & filter = filter_map(element_type);
if (!filter_map.exists(element_type, gt))
continue;
if (filter.size() == 0)
continue;
auto extra_volume_copy =
mat.getInternal<Real>("extra_volume")(element_type);
crack_volume += Math::reduce(extra_volume_copy);
}
/// do not communicate if model is multi-scale
if (not aka::is_of_type<SolidMechanicsModelRVE>(model)) {
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(crack_volume, SynchronizerOperation::_sum);
}
if (not this->phase_volumes.size())
computePhaseVolumes();
crack_volume /= this->phase_volumes[material_name];
}
/* ------------------------------------------------------------------ */
void ASRTools::dumpRve() { model.dump(); }
/* ------------------------------------------------------------------ */
void ASRTools::dumpRve(UInt dump_nb) { model.dump(dump_nb); }
/* ------------------------------------------------------------------------ */
// void ASRTools::applyBodyForce(const Real gravity = 9.81) {
// auto spatial_dimension = model.getSpatialDimension();
// model.assembleMassLumped();
// auto & mass = model.getMass();
// auto & force = model.getExternalForce();
// Vector<Real> gravity(spatial_dimension);
// gravity(1) = -gravity;
// for (auto && data : zip(make_view(mass, spatial_dimension),
// make_view(force, spatial_dimension))) {
// const auto & mass_vec = (std::get<0>(data));
// AKANTU_DEBUG_ASSERT(mass_vec.norm(), "Mass vector components are zero");
// auto & force_vec = (std::get<1>(data));
// force_vec += gravity * mass_vec;
// }
// }
/* ------------------------------------------------------------------- */
void ASRTools::insertASRCohesivesRandomly(const UInt & nb_insertions,
std::string facet_mat_name,
Real gap_ratio) {
AKANTU_DEBUG_IN();
// fill in the partition_border_nodes array
communicateFlagsOnNodes();
/// pick central facets and neighbors
pickFacetsRandomly(nb_insertions, facet_mat_name);
insertOppositeFacetsAndCohesives();
assignCrackNumbers();
insertGap(gap_ratio);
preventCohesiveInsertionInNeighbors();
AKANTU_DEBUG_OUT();
}
/* ------------------------------------------------------------------- */
void ASRTools::insertASRCohesivesRandomly3D(const UInt & nb_insertions,
std::string facet_mat_name,
Real /*gap_ratio*/) {
AKANTU_DEBUG_IN();
// fill in the partition_border_nodes array
communicateFlagsOnNodes();
/// pick central facets and neighbors
pickFacetsRandomly(nb_insertions, facet_mat_name);
insertOppositeFacetsAndCohesives();
assignCrackNumbers();
// insertGap3D(gap_ratio);
preventCohesiveInsertionInNeighbors();
AKANTU_DEBUG_OUT();
}
/* ------------------------------------------------------------------- */
void ASRTools::insertASRCohesiveLoops3D(const UInt & nb_insertions,
std::string facet_mat_name,
Real /*gap_ratio*/) {
AKANTU_DEBUG_IN();
// fill in the partition_border_nodes array
communicateFlagsOnNodes();
/// pick central facets and neighbors
auto inserted = closedFacetsLoopAroundPoint(nb_insertions, facet_mat_name);
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(inserted, SynchronizerOperation::_sum);
AKANTU_DEBUG_ASSERT(inserted, "No ASR sites were inserted across the domain");
insertOppositeFacetsAndCohesives();
assignCrackNumbers();
communicateCrackNumbers();
// insertGap3D(gap_ratio);
// preventCohesiveInsertionInNeighbors();
AKANTU_DEBUG_OUT();
}
/* ------------------------------------------------------------------- */
template <UInt dim>
UInt ASRTools::insertPreCracks(const UInt & nb_insertions,
std::string facet_mat_name) {
AKANTU_DEBUG_IN();
// fill in the partition_border_nodes array
communicateFlagsOnNodes();
/// pick central facets and neighbors
auto inserted = insertCohesiveLoops<dim>(nb_insertions, facet_mat_name);
auto totally_inserted{inserted};
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(totally_inserted, SynchronizerOperation::_sum);
AKANTU_DEBUG_ASSERT(totally_inserted,
"No ASR sites were inserted across the domain");
communicateCrackNumbers();
AKANTU_DEBUG_OUT();
return inserted;
}
template UInt ASRTools::insertPreCracks<2>(const UInt & nb_insertions,
std::string mat_name);
template UInt ASRTools::insertPreCracks<3>(const UInt & nb_insertions,
std::string mat_name);
/* -------------------------------------------------------------------------
*/
void ASRTools::insertASRCohesivesByCoords(const Matrix<Real> & positions,
Real gap_ratio) {
AKANTU_DEBUG_IN();
// fill in the border_nodes array
communicateFlagsOnNodes();
/// pick the facets to duplicate
pickFacetsByCoord(positions);
insertOppositeFacetsAndCohesives();
assignCrackNumbers();
insertGap(gap_ratio);
preventCohesiveInsertionInNeighbors();
AKANTU_DEBUG_OUT();
}
/* -------------------------------------------------------------------------
*/
void ASRTools::communicateFlagsOnNodes() {
auto & mesh = model.getMesh();
auto & synch = mesh.getElementSynchronizer();
NodesFlagUpdater nodes_flag_updater(mesh, synch,
this->partition_border_nodes);
nodes_flag_updater.fillPreventInsertion();
}
/* ------------------------------------------------------------------- */
void ASRTools::communicateEffStressesOnNodes() {
auto & mesh = model.getMesh();
auto & synch = mesh.getElementSynchronizer();
NodesEffStressUpdater nodes_eff_stress_updater(mesh, synch,
this->nodes_eff_stress);
nodes_eff_stress_updater.updateMaxEffStressAtNodes();
}
/* ------------------------------------------------------------------- */
void ASRTools::communicateCrackNumbers() {
AKANTU_DEBUG_IN();
if (model.getMesh().getCommunicator().getNbProc() == 1)
return;
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
const auto & coh_synch = coh_model.getCohesiveSynchronizer();
CrackNumbersUpdater crack_numbers_updater(model, coh_synch);
crack_numbers_updater.communicateCrackNumbers();
AKANTU_DEBUG_OUT();
}
/* ----------------------------------------------------------------------- */
void ASRTools::pickFacetsByCoord(const Matrix<Real> & positions) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto type = *mesh.elementTypes(dim, gt, _ek_regular).begin();
auto facet_type = Mesh::getFacetType(type);
auto & doubled_facets =
mesh_facets.createElementGroup("doubled_facets", dim - 1);
auto & doubled_nodes = mesh.createNodeGroup("doubled_nodes");
auto & facet_conn = mesh_facets.getConnectivity(facet_type, gt);
auto & check_facets = inserter.getCheckFacets(facet_type, gt);
const UInt nb_nodes_facet = facet_conn.getNbComponent();
const auto facet_conn_it = make_view(facet_conn, nb_nodes_facet).begin();
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
Vector<Real> bary_facet(dim);
for (const auto & position : positions) {
Real min_dist = std::numeric_limits<Real>::max();
Element cent_facet;
cent_facet.ghost_type = gt;
for_each_element(
mesh_facets,
[&](auto && facet) {
if (check_facets(facet.element)) {
mesh_facets.getBarycenter(facet, bary_facet);
auto dist = std::abs(bary_facet.distance(position));
if (dist < min_dist) {
min_dist = dist;
cent_facet = facet;
}
}
},
_spatial_dimension = dim - 1, _ghost_type = _not_ghost);
/// communicate between processors for the element closest to the position
auto local_min_dist = min_dist;
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(min_dist, SynchronizerOperation::_min);
/// let other processor insert the cohesive at this position
if (local_min_dist != min_dist)
continue;
/// eliminate possibility of inserting on a partition border
bool border_facets{false};
Vector<UInt> facet_nodes = facet_conn_it[cent_facet.element];
for (auto node : facet_nodes) {
if (this->partition_border_nodes(node))
border_facets = true;
}
if (border_facets) {
std::cout << "Facet at the position " << position(0) << "," << position(1)
<< " is close to the partition border. Skipping this position"
<< std::endl;
continue;
}
/// eliminate possibility of intersecting existing ASR element
bool intersection{false};
for (auto node : facet_nodes) {
if (this->ASR_nodes(node))
intersection = true;
}
if (intersection) {
std::cout
<< "Facet at the position " << position(0) << "," << position(1)
<< " is intersecting another ASR element. Skipping this position"
<< std::endl;
continue;
} else {
auto success_with_neighbors = pickFacetNeighbors(cent_facet);
if (success_with_neighbors) {
doubled_facets.add(cent_facet);
/// add all facet nodes to the group
for (auto node : arange(nb_nodes_facet)) {
doubled_nodes.add(facet_conn(cent_facet.element, node));
this->ASR_nodes(facet_conn(cent_facet.element, node)) = true;
}
std::cout << "Proc " << prank << " placed 1 ASR site" << std::endl;
continue;
} else
continue;
}
}
}
/* ------------------------------------------------------------------- */
void ASRTools::pickFacetsRandomly(UInt nb_insertions,
std::string facet_mat_name) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto type = *mesh.elementTypes(dim, gt, _ek_regular).begin();
auto facet_type = Mesh::getFacetType(type);
auto & doubled_facets =
mesh_facets.createElementGroup("doubled_facets", dim - 1);
auto & doubled_nodes = mesh.createNodeGroup("doubled_nodes");
auto & matrix_elements =
mesh_facets.createElementGroup("matrix_facets", dim - 1);
auto facet_material_id = model.getMaterialIndex(facet_mat_name);
auto & facet_conn = mesh_facets.getConnectivity(facet_type, gt);
const UInt nb_nodes_facet = facet_conn.getNbComponent();
const auto facet_conn_it = make_view(facet_conn, nb_nodes_facet).begin();
auto & check_facets = inserter.getCheckFacets(facet_type, gt);
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
if (not nb_insertions)
return;
Vector<Real> bary_facet(dim);
for_each_element(
mesh_facets,
[&](auto && facet) {
if (check_facets(facet.element)) {
mesh_facets.getBarycenter(facet, bary_facet);
auto & facet_material = coh_model.getFacetMaterial(
facet.type, facet.ghost_type)(facet.element);
if (facet_material == facet_material_id)
matrix_elements.add(facet);
}
},
_spatial_dimension = dim - 1, _ghost_type = _not_ghost);
UInt nb_element = matrix_elements.getElements(facet_type).size();
UInt seed = RandomGenerator<UInt>::seed();
std::mt19937 random_generator(seed);
std::uniform_int_distribution<> dis(0, nb_element - 1);
if (not nb_element) {
std::cout << "Proc " << prank << " couldn't place " << nb_insertions
<< " ASR sites" << std::endl;
return;
}
UInt already_inserted = 0;
while (already_inserted < nb_insertions) {
auto id = dis(random_generator);
Element cent_facet;
cent_facet.type = facet_type;
cent_facet.element = matrix_elements.getElements(facet_type)(id);
cent_facet.ghost_type = gt;
/// eliminate possibility of inserting on a partition border or
/// intersecting
bool border_facets{false};
Vector<UInt> facet_nodes = facet_conn_it[cent_facet.element];
for (auto node : facet_nodes) {
if (this->partition_border_nodes(node) or this->ASR_nodes(node))
border_facets = true;
}
if (border_facets)
continue;
else {
auto success_with_neighbors = pickFacetNeighbors(cent_facet);
if (success_with_neighbors) {
already_inserted++;
doubled_facets.add(cent_facet);
/// add all facet nodes to the group
for (auto node : arange(nb_nodes_facet)) {
doubled_nodes.add(facet_conn(cent_facet.element, node));
this->ASR_nodes(facet_conn(cent_facet.element, node)) = true;
}
std::cout << "Proc " << prank << " placed 1 ASR site" << std::endl;
continue;
} else
continue;
}
}
}
/* ------------------------------------------------------------------- */
UInt ASRTools::closedFacetsLoopAroundPoint(UInt nb_insertions,
std::string mat_name) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto element_type = *mesh.elementTypes(dim, gt, _ek_regular).begin();
auto facet_type = Mesh::getFacetType(element_type);
auto & doubled_facets =
mesh_facets.createElementGroup("doubled_facets", dim - 1);
auto & doubled_nodes = mesh.createNodeGroup("doubled_nodes");
auto material_id = model.getMaterialIndex(mat_name);
auto & facet_conn = mesh_facets.getConnectivity(facet_type, gt);
const UInt nb_nodes_facet = facet_conn.getNbComponent();
const auto facet_conn_it = make_view(facet_conn, nb_nodes_facet).begin();
auto & node_conn = mesh_facets.getConnectivity(_point_1, gt);
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
const Real max_dot{0.7};
if (not nb_insertions)
return 0;
CSR<Element> nodes_to_facets;
MeshUtils::buildNode2Elements(mesh_facets, nodes_to_facets, dim - 1);
std::set<UInt> matrix_nodes;
for_each_element(
mesh_facets,
[&](auto && point_el) {
// get the node number
auto node = node_conn(point_el.element);
// discard ghost nodes
if (mesh.isPureGhostNode(node))
goto nextnode;
for (auto & facet : nodes_to_facets.getRow(node)) {
auto & facet_material = coh_model.getFacetMaterial(
facet.type, facet.ghost_type)(facet.element);
if (facet_material != material_id) {
goto nextnode;
}
}
matrix_nodes.emplace(node);
nextnode:;
},
_spatial_dimension = 0, _ghost_type = _not_ghost);
UInt nb_nodes = matrix_nodes.size();
UInt seed = RandomGenerator<UInt>::seed();
std::mt19937 random_generator(seed);
std::uniform_int_distribution<> dis(0, nb_nodes - 1);
if (not nb_nodes) {
std::cout << "Proc " << prank << " couldn't place " << nb_insertions
<< " ASR sites" << std::endl;
return 0;
}
UInt already_inserted = 0;
std::set<UInt> left_nodes = matrix_nodes;
while (already_inserted < nb_insertions) {
if (not left_nodes.size()) {
std::cout << "Proc " << prank << " inserted " << already_inserted
<< " ASR sites out of " << nb_insertions << std::endl;
return already_inserted;
}
auto id = dis(random_generator);
auto it = matrix_nodes.begin();
std::advance(it, id);
UInt cent_node(*it);
left_nodes.erase(*it);
// not touching other cracks
if (this->ASR_nodes(cent_node))
continue;
// поехали
CSR<Element> segments_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, segments_to_nodes, dim - 2);
auto && segments_to_node = segments_to_nodes.getRow(cent_node);
Array<Element> segments_list;
for (auto && segment : segments_to_node) {
segments_list.push_back(segment);
}
// pick the first non-ghost segment in the list
Element starting_segment;
for (auto segment : segments_list) {
if (segment.ghost_type == _not_ghost) {
starting_segment = segment;
break;
}
}
// go to next node if starting segment could not be picked
if (starting_segment == ElementNull) {
std::cout
<< "Could not pick the starting segment, switching to the next node"
<< std::endl;
continue;
}
auto & facets_to_segment =
mesh_facets.getElementToSubelement(starting_segment);
// pick the first good facet in the list
Element starting_facet{ElementNull};
for (const auto & facet : facets_to_segment) {
// check if the facet and its nodes are ok
if (isFacetAndNodesGood(facet, material_id, true)) {
starting_facet = facet;
break;
}
}
// go to next node if starting facet could not be picked
if (starting_facet == ElementNull) {
std::cout
<< "Could not pick the starting facet, switching to the next node"
<< std::endl;
continue;
}
// call the actual function that build the bridge
auto facets_in_loop = findFacetsLoopFromSegment2Segment(
starting_facet, starting_segment, starting_segment, cent_node, max_dot,
material_id, true);
// loop broke -> try another point
if (not facets_in_loop.size()) {
std::cout << "Couldn't close the facet loop, taking the next node"
<< std::endl;
continue;
}
// otherwise champaigne
for (auto & facet : facets_in_loop) {
doubled_facets.add(facet);
/// add all facet nodes to the group
for (auto node : arange(nb_nodes_facet)) {
doubled_nodes.add(facet_conn(facet.element, node));
this->ASR_nodes(facet_conn(facet.element, node)) = true;
}
}
this->asr_central_nodes.push_back(cent_node);
// store the asr facets
// this->ASR_facets_from_mesh_facets.push_back(facets_in_loop);
already_inserted++;
}
std::cout << "Proc " << prank << " placed " << already_inserted << " ASR site"
<< std::endl;
return already_inserted;
}
/* ------------------------------------------------------------------- */
template <UInt dim>
UInt ASRTools::insertCohesiveLoops(UInt nb_insertions, std::string mat_name) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
const GhostType gt = _not_ghost;
auto element_type = *mesh.elementTypes(dim, gt, _ek_regular).begin();
auto facet_type = Mesh::getFacetType(element_type);
auto material_id = model.getMaterialIndex(mat_name);
auto & facet_conn = mesh_facets.getConnectivity(facet_type, gt);
const UInt nb_nodes_facet = facet_conn.getNbComponent();
const auto facet_conn_it = make_view(facet_conn, nb_nodes_facet).begin();
auto & node_conn = mesh_facets.getConnectivity(_point_1, gt);
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
const Real max_dot{0.7};
// instantiate crack_numbers array
for (auto && type_facet : mesh_facets.elementTypes(dim - 1)) {
ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet);
mesh.getDataPointer<UInt>("crack_numbers", type_cohesive);
}
ElementType type_cohesive = FEEngine::getCohesiveElementType(facet_type);
auto & crack_numbers = mesh.getData<UInt>("crack_numbers", type_cohesive);
CSR<Element> nodes_to_facets;
MeshUtils::buildNode2Elements(mesh_facets, nodes_to_facets, dim - 1);
std::set<UInt> matrix_nodes;
for_each_element(
mesh_facets,
[&](auto && point_el) {
// get the node number
auto node = node_conn(point_el.element);
// discard ghost nodes
if (mesh.isPureGhostNode(node))
goto nextnode;
for (auto & facet : nodes_to_facets.getRow(node)) {
auto & facet_material = coh_model.getFacetMaterial(
facet.type, facet.ghost_type)(facet.element);
if (facet_material != material_id) {
goto nextnode;
}
}
matrix_nodes.emplace(node);
nextnode:;
},
_spatial_dimension = 0, _ghost_type = _not_ghost);
UInt nb_nodes = matrix_nodes.size();
UInt seed = RandomGenerator<UInt>::seed();
std::mt19937 random_generator(seed);
std::uniform_int_distribution<> dis(0, nb_nodes - 1);
UInt already_inserted = 0;
std::set<UInt> left_nodes = matrix_nodes;
Array<Array<Element>> loops;
while (already_inserted < nb_insertions and nb_nodes and left_nodes.size()) {
auto id = dis(random_generator);
auto it = matrix_nodes.begin();
std::advance(it, id);
UInt cent_node(*it);
left_nodes.erase(*it);
// not touching other cracks
if (this->ASR_nodes(cent_node))
continue;
// поехали
CSR<Element> segments_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, segments_to_nodes, dim - 2);
auto && segments_to_node = segments_to_nodes.getRow(cent_node);
Array<Element> segments_list;
for (auto && segment : segments_to_node) {
segments_list.push_back(segment);
}
// pick the first non-ghost segment in the list
Element starting_segment;
for (auto segment : segments_list) {
if (segment.ghost_type == _not_ghost) {
starting_segment = segment;
break;
}
}
// go to next node if starting segment could not be picked
if (starting_segment == ElementNull) {
std::cout
<< "Could not pick the starting segment, switching to the next node"
<< std::endl;
continue;
}
auto & facets_to_segment =
mesh_facets.getElementToSubelement(starting_segment);
// pick the first good facet in the list
Element starting_facet{ElementNull};
for (const auto & facet : facets_to_segment) {
// check if the facet and its nodes are ok
if (isFacetAndNodesGood(facet, material_id, true)) {
starting_facet = facet;
break;
}
}
// go to next node if starting facet could not be picked
if (starting_facet == ElementNull) {
std::cout
<< "Could not pick the starting facet, switching to the next node"
<< std::endl;
continue;
}
// call the actual function that build the bridge
auto facets_in_loop = findFacetsLoopFromSegment2Segment(
starting_facet, starting_segment, starting_segment, cent_node, max_dot,
material_id, true);
// loop broke -> try another point
if (not facets_in_loop.size()) {
std::cout << "Couldn't close the facet loop, taking the next node"
<< std::endl;
continue;
}
// otherwise champaigne
loops.push_back(facets_in_loop);
for (auto & facet : facets_in_loop) {
/// add all facet nodes to the group
for (auto node : arange(nb_nodes_facet)) {
this->ASR_nodes(facet_conn(facet.element, node)) = true;
}
}
this->asr_central_nodes.push_back(cent_node);
already_inserted++;
}
/// shift crack numbers by the number of cracks on lower processors
auto num_cracks = loops.size();
comm.exclusiveScan(num_cracks);
// convert loops into a map
std::map<UInt, UInt> facet_nbs_crack_nbs;
for (auto && data : enumerate(loops)) {
auto crack_nb = std::get<0>(data) + num_cracks;
auto && facet_loop = std::get<1>(data);
for (auto && facet : facet_loop) {
facet_nbs_crack_nbs[facet.element] = crack_nb;
}
}
// insert cohesives in a corresponding material
auto & mat = model.getMaterial(material_id);
auto * mat_coh = dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
AKANTU_DEBUG_ASSERT(mat_coh != nullptr,
"Chosen material is not linear sequential");
mat_coh->insertCohesiveElements(facet_nbs_crack_nbs, facet_type, false);
// extend crack numbers array
for (auto && pair : facet_nbs_crack_nbs) {
auto && crack_nb = pair.second;
crack_numbers.push_back(crack_nb);
}
inserter.insertElements();
// fill up ASR facets vector
this->asr_facets.resize(loops.size());
for (auto && data : zip(loops, this->asr_facets)) {
auto && facet_loop = std::get<0>(data);
auto && asr_facet_loop = std::get<1>(data);
for (auto & facet : facet_loop) {
Element cohesive{ElementNull};
auto & connected_els = mesh_facets.getElementToSubelement(facet);
for (auto & connected_el : connected_els) {
if (mesh.getKind(connected_el.type) == _ek_cohesive) {
cohesive = connected_el;
break;
}
}
AKANTU_DEBUG_ASSERT(cohesive != ElementNull,
"Connected cohesive element not identified");
auto && connected_subels = mesh_facets.getSubelementToElement(cohesive);
for (auto & connected_subel : connected_subels) {
if (connected_subel.type != facet.type)
continue;
asr_facet_loop.push_back(connected_subel);
}
}
}
// split nodes into pairs and compute averaged normals
identifyASRCentralNodePairsAndNormals();
std::cout << "Proc " << prank << " placed " << already_inserted << " ASR site"
<< std::endl;
return already_inserted;
}
template UInt ASRTools::insertCohesiveLoops<2>(UInt nb_insertions,
std::string mat_name);
template UInt ASRTools::insertCohesiveLoops<3>(UInt nb_insertions,
std::string mat_name);
/* ------------------------------------------------------------------- */
Array<Element> ASRTools::findFacetsLoopFromSegment2Segment(
Element directional_facet, Element starting_segment, Element ending_segment,
UInt cent_node, Real max_dot, UInt material_id, bool check_asr_nodes) {
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(
dim == 3, "findFacetsLoopFromSegment2Segment currently supports only 3D");
AKANTU_DEBUG_ASSERT(Mesh::getSpatialDimension(directional_facet.type) ==
dim - 1,
"Directional facet provided has wrong spatial dimension");
if (Mesh::getSpatialDimension(starting_segment.type) != dim - 2 or
Mesh::getSpatialDimension(ending_segment.type) != dim - 2) {
AKANTU_EXCEPTION("Starting facet provided has wrong spatial dimension");
}
// get the point el corresponding to the central node
CSR<Element> points_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, points_to_nodes, 0);
auto && points_to_node = points_to_nodes.getRow(cent_node);
auto point_el = *points_to_node.begin();
AKANTU_DEBUG_ASSERT(point_el.type == _point_1,
"Provided node element type is wrong");
// check if the provided node is shared by two segments
auto & segments_to_node = mesh_facets.getElementToSubelement(point_el);
auto ret1 = std::find(segments_to_node.begin(), segments_to_node.end(),
starting_segment);
AKANTU_DEBUG_ASSERT(ret1 != segments_to_node.end(),
"Starting segment doesn't contain the central node");
auto ret2 = std::find(segments_to_node.begin(), segments_to_node.end(),
ending_segment);
AKANTU_DEBUG_ASSERT(ret2 != segments_to_node.end(),
"Ending segment doesn't contain the central node");
// check if the directional facet contain starting segment
auto & facets_to_segment =
mesh_facets.getElementToSubelement(starting_segment);
auto ret3 = std::find(facets_to_segment.begin(), facets_to_segment.end(),
directional_facet);
AKANTU_DEBUG_ASSERT(ret3 != facets_to_segment.end(),
"Starting facet doesn't contain the starting segment");
// loop through facets to arrive from the starting segment to the endin
bool loop_closed{false};
auto current_facet(directional_facet);
auto border_segment(starting_segment);
Array<Element> facets_in_loop;
Array<Element> segments_in_loop;
while (not loop_closed and facets_in_loop.size() < 10) {
// loop through all the neighboring facets and pick the prettiest
Element next_facet(ElementNull);
Real current_facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, current_facet);
bool almost_closed{false};
auto neighbor_facets = mesh_facets.getElementToSubelement(border_segment);
for (auto neighbor_facet : neighbor_facets) {
if (neighbor_facet == current_facet)
continue;
if (not isFacetAndNodesGood(neighbor_facet, material_id, check_asr_nodes))
continue;
// first check if it has the ending segment -> loop closed
bool ending_segment_touched{false};
if (facets_in_loop.size()) {
const Vector<Element> neighbors_segments =
mesh_facets.getSubelementToElement(neighbor_facet);
auto ret = std::find(neighbors_segments.begin(),
neighbors_segments.end(), ending_segment);
if (ret != neighbors_segments.end()) {
ending_segment_touched = true;
almost_closed = true;
}
}
// conditions on the angle between facets
Real neighbor_facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, neighbor_facet);
Real hypotenuse = sqrt(neighbor_facet_indiam * neighbor_facet_indiam +
current_facet_indiam * current_facet_indiam) /
2;
auto dist = MeshUtils::distanceBetweenIncentersCorrected(
mesh_facets, current_facet, neighbor_facet);
if (dist < hypotenuse) {
continue;
}
// get abs of dot product between two normals
Real dot = MeshUtils::cosSharpAngleBetween2Facets(model, current_facet,
neighbor_facet);
if (dot > max_dot) {
next_facet = neighbor_facet;
if (ending_segment_touched) {
facets_in_loop.push_back(neighbor_facet);
loop_closed = true;
break;
}
}
}
if (next_facet == ElementNull) {
facets_in_loop.clear();
return facets_in_loop;
}
if (almost_closed & not loop_closed) {
facets_in_loop.clear();
return facets_in_loop;
}
if (loop_closed) {
return facets_in_loop;
}
// otherwise make this facet a current one
current_facet = next_facet;
facets_in_loop.push_back(current_facet);
segments_in_loop.push_back(border_segment);
// identify the next border segment
auto previous_border_segment = border_segment;
border_segment = ElementNull;
const Vector<Element> current_segments =
mesh_facets.getSubelementToElement(current_facet);
for (auto & segment : current_segments) {
if (segment == previous_border_segment)
continue;
// check if the segment includes the central node
auto && nodes_to_segment = mesh_facets.getConnectivity(segment);
bool includes_cent_node{false};
for (auto & node : nodes_to_segment) {
if (node == cent_node) {
includes_cent_node = true;
break;
}
}
if (not includes_cent_node)
continue;
// check if the segment was previously added
if (segments_in_loop.find(segment) != UInt(-1))
continue;
border_segment = segment;
break;
}
if (border_segment == ElementNull) {
facets_in_loop.clear();
return facets_in_loop;
}
}
return facets_in_loop;
}
/* ------------------------------------------------------------------- */
Array<Element>
ASRTools::findFacetsLoopByGraphByDist(const Array<Element> & limit_facets,
const Array<Element> & limit_segments,
const UInt & cent_node) {
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
Array<Element> facets_in_loop;
auto && starting_facet = limit_facets(0);
auto && ending_facet = limit_facets(1);
auto && starting_segment = limit_segments(0);
auto && ending_segment = limit_segments(1);
Real max_dist = std::numeric_limits<Real>::min();
// Create a struct to hold properties for each vertex
typedef struct vertex_properties {
Element segment;
} vertex_properties_t;
// Create a struct to hold properties for each edge
typedef struct edge_properties {
Element facet;
Real weight;
} edge_properties_t;
// Define the type of the graph
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
vertex_properties_t, edge_properties_t>
graph_t;
typedef graph_t::vertex_descriptor vertex_descriptor_t;
typedef graph_t::edge_descriptor edge_descriptor_t;
typedef boost::graph_traits<graph_t>::edge_iterator edge_iter;
typedef boost::graph_traits<graph_t>::vertex_iterator vertex_iter;
graph_t g;
// prepare the list of facets sharing the central node
CSR<Element> facets_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, facets_to_nodes, dim - 1);
auto && facets_to_node = facets_to_nodes.getRow(cent_node);
std::set<Element> facets_added;
std::map<Element, vertex_descriptor_t> segment_vertex_map;
// get the point el corresponding to the central node
CSR<Element> points_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, points_to_nodes, 0);
auto && points_to_node = points_to_nodes.getRow(cent_node);
auto point_el = *points_to_node.begin();
// get list of all segments connected to the node
auto && segm_to_point = mesh_facets.getElementToSubelement(point_el);
// add starting and ending segment to the graph
vertex_descriptor_t v_start = boost::add_vertex(g);
g[v_start].segment = starting_segment;
vertex_descriptor_t v_end = boost::add_vertex(g);
g[v_end].segment = ending_segment;
segment_vertex_map[starting_segment] = v_start;
segment_vertex_map[ending_segment] = v_end;
for (auto && facet : facets_to_node) {
// discard undesired facets first
if (facet == starting_facet or facet == ending_facet)
continue;
if (not isFacetAndNodesGood(facet))
continue;
if (belong2SameElement(starting_facet, facet) or
belong2SameElement(ending_facet, facet))
continue;
// identify 2 side facets
Array<Element> side_segments;
auto && facet_segments = mesh_facets.getSubelementToElement(facet);
for (auto & segment : facet_segments) {
auto ret = std::find(segm_to_point.begin(), segm_to_point.end(), segment);
if (ret != segm_to_point.end()) {
side_segments.push_back(segment);
}
}
AKANTU_DEBUG_ASSERT(side_segments.size() == 2,
"Number of side facets is wrong");
// add corresponding vertex (if not there)and edge into graph
Array<vertex_descriptor_t> v(2);
for (UInt i = 0; i < 2; i++) {
auto it = segment_vertex_map.find(side_segments(i));
if (it != segment_vertex_map.end()) {
v(i) = it->second;
} else {
v(i) = boost::add_vertex(g);
g[v(i)].segment = side_segments(i);
segment_vertex_map[side_segments(i)] = v(i);
}
}
// add corresponding edge into the graph
auto ret = facets_added.emplace(facet);
if (ret.second) {
// compute facet's area to use as a weight
// auto facet_area = MeshUtils::getFacetArea(model, facet);
auto dist = MeshUtils::distanceBetweenIncenters(mesh_facets,
starting_facet, facet);
dist +=
MeshUtils::distanceBetweenIncenters(mesh_facets, ending_facet, facet);
if (dist > max_dist)
max_dist = dist;
// add edge
std::pair<edge_descriptor_t, bool> e = boost::add_edge(v(0), v(1), g);
g[e.first].weight = dist;
// g[e.first].weight = facet_area;
g[e.first].facet = facet;
}
}
// normalize and flip weights
edge_iter ei, ei_end;
for (std::tie(ei, ei_end) = boost::edges(g); ei != ei_end; ++ei) {
auto weight = g[*ei].weight;
weight = max_dist - weight;
// weight = std::pow(weight, 4);//give less weight for smaller values
auto facet_area = MeshUtils::getFacetArea(model, g[*ei].facet);
g[*ei].weight = weight + sqrt(facet_area);
}
// Print out some useful information
std::cout << "Starting segm " << starting_segment.element << " ending segm "
<< ending_segment.element << std::endl;
std::cout << "Graph:" << std::endl;
for (std::tie(ei, ei_end) = boost::edges(g); ei != ei_end; ++ei) {
std::cout << g[*ei].facet.element << " ";
}
std::cout << std::endl;
std::cout << "num_verts: " << boost::num_vertices(g) << std::endl;
std::cout << "num_edges: " << boost::num_edges(g) << std::endl;
// BGL Dijkstra's Shortest Paths here...
std::vector<Real> distances(boost::num_vertices(g));
std::vector<vertex_descriptor_t> predecessors(boost::num_vertices(g));
boost::dijkstra_shortest_paths(
g, v_start,
boost::weight_map(boost::get(&edge_properties_t::weight, g))
.distance_map(boost::make_iterator_property_map(
distances.begin(), boost::get(boost::vertex_index, g)))
.predecessor_map(boost::make_iterator_property_map(
predecessors.begin(), boost::get(boost::vertex_index, g))));
std::cout << "distances and parents:" << std::endl;
vertex_iter vi, vend;
for (boost::tie(vi, vend) = boost::vertices(g); vi != vend; ++vi) {
std::cout << "distance(" << g[*vi].segment.element
<< ") = " << distances[*vi] << ", ";
std::cout << "parent = " << g[predecessors[*vi]].segment.element
<< std::endl;
}
// Extract the shortest path from v1 to v3.
typedef std::vector<edge_descriptor_t> path_t;
path_t path;
vertex_descriptor_t v = v_end;
for (vertex_descriptor_t u = predecessors[v]; u != v;
v = u, u = predecessors[v]) {
std::pair<edge_descriptor_t, bool> edge_pair = boost::edge(u, v, g);
path.push_back(edge_pair.first);
}
std::cout << std::endl;
std::cout << "Shortest Path from segment " << starting_segment.element
<< " to " << ending_segment.element << ":" << std::endl;
for (path_t::reverse_iterator riter = path.rbegin(); riter != path.rend();
++riter) {
vertex_descriptor_t u_tmp = boost::source(*riter, g);
vertex_descriptor_t v_tmp = boost::target(*riter, g);
edge_descriptor_t e_tmp = boost::edge(u_tmp, v_tmp, g).first;
std::cout << " " << g[u_tmp].segment.element << " -> "
<< g[v_tmp].segment.element << " through "
<< g[e_tmp].facet.element << " (area: " << g[e_tmp].weight
<< ")" << std::endl;
facets_in_loop.push_back(g[e_tmp].facet);
}
return facets_in_loop;
}
/* ------------------------------------------------------------------- */
Array<Element> ASRTools::findFacetsLoopByGraphByArea(
const Array<Element> & limit_facets, const Array<Element> & limit_segments,
const Array<Element> & preinserted_facets, const UInt & cent_node) {
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
Array<Element> facets_in_loop;
// find two best neighbors
Array<Element> best_neighbors(2, 1, ElementNull);
Array<Element> neighbors_borders(2, 1, ElementNull);
for (UInt i = 0; i < 2; i++) {
Element best_neighbor{ElementNull};
// if the facet is already provided - use it
if (preinserted_facets(i) != ElementNull) {
best_neighbor = preinserted_facets(i);
} else {
// if not - search for it
auto limit_facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, limit_facets(i));
auto max_dot = std::numeric_limits<Real>::min();
auto && neighbor_facets =
mesh_facets.getElementToSubelement(limit_segments(i));
for (auto && neighbor_facet : neighbor_facets) {
if (neighbor_facet == limit_facets(0) or
neighbor_facet == limit_facets(1))
continue;
if (not isFacetAndNodesGood(neighbor_facet))
continue;
// conditions on the angle between facets
Real neighbor_facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, neighbor_facet);
Real hypotenuse = sqrt(neighbor_facet_indiam * neighbor_facet_indiam +
limit_facet_indiam * limit_facet_indiam) /
2;
auto dist = MeshUtils::distanceBetweenIncentersCorrected(
mesh_facets, limit_facets(i), neighbor_facet);
if (dist < hypotenuse)
continue;
// find neighbor with the biggest thing
// get abs of dot product between two normals
Real dot = MeshUtils::cosSharpAngleBetween2Facets(
model, limit_facets(i), neighbor_facet);
if (dot > max_dot) {
max_dot = dot;
best_neighbor = neighbor_facet;
}
}
}
if (best_neighbor == ElementNull) {
return facets_in_loop;
} else {
best_neighbors(i) = best_neighbor;
}
// find new limiting segments
auto && neighbor_segments =
mesh_facets.getSubelementToElement(best_neighbor);
for (auto & segment : neighbor_segments) {
if (segment == limit_segments(i))
continue;
// check if the segment includes the central node
auto && nodes_to_segment = mesh_facets.getConnectivity(segment);
bool includes_cent_node{false};
for (auto & node : nodes_to_segment) {
if (node == cent_node) {
includes_cent_node = true;
break;
}
}
if (not includes_cent_node)
continue;
neighbors_borders(i) = segment;
break;
}
}
// check if borders are not the same segment
if (neighbors_borders(0) == neighbors_borders(1)) {
for (auto && best_neighbor : best_neighbors) {
facets_in_loop.push_back(best_neighbor);
}
}
// Create a struct to hold properties for each vertex
typedef struct vertex_properties {
Element segment;
} vertex_properties_t;
// Create a struct to hold properties for each edge
typedef struct edge_properties {
Element facet;
Real weight;
} edge_properties_t;
// Define the type of the graph
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
vertex_properties_t, edge_properties_t>
graph_t;
typedef graph_t::vertex_descriptor vertex_descriptor_t;
typedef graph_t::edge_descriptor edge_descriptor_t;
// typedef boost::graph_traits<graph_t>::edge_iterator edge_iter;
// typedef boost::graph_traits<graph_t>::vertex_iterator vertex_iter;
graph_t g;
// prepare the list of facets sharing the central node
CSR<Element> facets_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, facets_to_nodes, dim - 1);
auto && facets_to_node = facets_to_nodes.getRow(cent_node);
std::set<Element> facets_added;
std::map<Element, vertex_descriptor_t> segment_vertex_map;
// get the point el corresponding to the central node
CSR<Element> points_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, points_to_nodes, 0);
auto && points_to_node = points_to_nodes.getRow(cent_node);
auto point_el = *points_to_node.begin();
// get list of all segments connected to the node
auto && segm_to_point = mesh_facets.getElementToSubelement(point_el);
// add starting and ending segment to the graph
vertex_descriptor_t v_start = boost::add_vertex(g);
g[v_start].segment = neighbors_borders(0);
vertex_descriptor_t v_end = boost::add_vertex(g);
g[v_end].segment = neighbors_borders(1);
segment_vertex_map[neighbors_borders(0)] = v_start;
segment_vertex_map[neighbors_borders(1)] = v_end;
// compute inscribed circles diameters
Array<Real> best_neighbors_indiam;
for (auto && best_neighbor : best_neighbors) {
auto neighbor_facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, best_neighbor);
best_neighbors_indiam.push_back(neighbor_facet_indiam);
}
for (auto && facet : facets_to_node) {
// discard undesired facets first
if (facet == best_neighbors(0) or facet == best_neighbors(1) or
facet == limit_facets(0) or facet == limit_facets(1))
continue;
if (not isFacetAndNodesGood(facet))
continue;
if (belong2SameElement(best_neighbors(0), facet) or
belong2SameElement(best_neighbors(1), facet) or
belong2SameElement(limit_facets(0), facet) or
belong2SameElement(limit_facets(1), facet))
continue;
// discard short distances to starting and ending facets
bool short_dist{false};
auto facet_indiam = MeshUtils::getInscribedCircleDiameter(model, facet);
for (UInt i = 0; i < 2; i++) {
auto hypotenuse =
sqrt(best_neighbors_indiam(i) * best_neighbors_indiam(i) +
facet_indiam * facet_indiam) /
2;
auto dist = MeshUtils::distanceBetweenIncenters(mesh_facets,
best_neighbors(i), facet);
if (dist <= hypotenuse) {
short_dist = true;
break;
}
}
if (short_dist)
continue;
// identify 2 side facets
Array<Element> side_segments;
auto && facet_segments = mesh_facets.getSubelementToElement(facet);
for (auto & segment : facet_segments) {
auto ret = std::find(segm_to_point.begin(), segm_to_point.end(), segment);
if (ret != segm_to_point.end()) {
side_segments.push_back(segment);
}
}
AKANTU_DEBUG_ASSERT(side_segments.size() == 2,
"Number of side facets is wrong");
// add corresponding vertex (if not there)and edge into graph
Array<vertex_descriptor_t> v(2);
for (UInt i = 0; i < 2; i++) {
auto it = segment_vertex_map.find(side_segments(i));
if (it != segment_vertex_map.end()) {
v(i) = it->second;
} else {
v(i) = boost::add_vertex(g);
g[v(i)].segment = side_segments(i);
segment_vertex_map[side_segments(i)] = v(i);
}
}
// add corresponding edge into the graph
auto ret = facets_added.emplace(facet);
if (ret.second) {
// compute facet's area to use as a weight
auto facet_area = MeshUtils::getFacetArea(model, facet);
// add edge
std::pair<edge_descriptor_t, bool> e = boost::add_edge(v(0), v(1), g);
g[e.first].weight = facet_area;
g[e.first].facet = facet;
}
}
// // Print out some useful information
// std::cout << "Starting facet " << best_neighbors(0).element
// << " ending facet " << best_neighbors(0).element << std::endl;
// std::cout << "Graph:" << std::endl;
// // boost::print_graph(g, boost::get(&vertex_properties_t::segment, g));
// edge_iter ei, ei_end;
// for (std::tie(ei, ei_end) = boost::edges(g); ei != ei_end; ++ei) {
// std::cout << g[*ei].facet.element << ",";
// }
// std::cout << std::endl;
// for (std::tie(ei, ei_end) = boost::edges(g); ei != ei_end; ++ei) {
// vertex_descriptor_t u = boost::source(*ei, g);
// vertex_descriptor_t v = boost::target(*ei, g);
// std::cout << g[*ei].facet.element << " from " << g[u].segment.element
// << "->" << g[v].segment.element << " area " << g[*ei].weight
// << std::endl;
// }
// std::cout << "num_verts: " << boost::num_vertices(g) << std::endl;
// std::cout << "num_edges: " << boost::num_edges(g) << std::endl;
// std::cout << std::endl;
// BGL Dijkstra's Shortest Paths here...
std::vector<Real> distances(boost::num_vertices(g));
std::vector<vertex_descriptor_t> predecessors(boost::num_vertices(g));
boost::dijkstra_shortest_paths(
g, v_end,
boost::weight_map(boost::get(&edge_properties_t::weight, g))
.distance_map(boost::make_iterator_property_map(
distances.begin(), boost::get(boost::vertex_index, g)))
.predecessor_map(boost::make_iterator_property_map(
predecessors.begin(), boost::get(boost::vertex_index, g))));
// Extract the shortest path from v1 to v3.
typedef std::vector<edge_descriptor_t> path_t;
path_t path;
vertex_descriptor_t v = v_start;
for (vertex_descriptor_t u = predecessors[v]; u != v;
v = u, u = predecessors[v]) {
std::pair<edge_descriptor_t, bool> edge_pair = boost::edge(u, v, g);
path.push_back(edge_pair.first);
}
if (path.size()) {
// add 2 determenistic facets
for (auto && best_neighbor : best_neighbors) {
facets_in_loop.push_back(best_neighbor);
}
// add the shortest path facets
for (path_t::reverse_iterator riter = path.rbegin(); riter != path.rend();
++riter) {
vertex_descriptor_t u_tmp = boost::source(*riter, g);
vertex_descriptor_t v_tmp = boost::target(*riter, g);
edge_descriptor_t e_tmp = boost::edge(u_tmp, v_tmp, g).first;
facets_in_loop.push_back(g[e_tmp].facet);
}
}
return facets_in_loop;
}
/* ------------------------------------------------------------------- */
Array<Element> ASRTools::findStressedFacetLoopAroundNode(
const Array<Element> & limit_facets, const Array<Element> & limit_segments,
const UInt & cent_node, Real min_dot) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(limit_facets(0) != limit_facets(1),
"Limit facets are equal");
AKANTU_DEBUG_ASSERT(limit_segments(0) != limit_segments(1),
"Limit segments are equal");
AKANTU_DEBUG_ASSERT(
dim == 3, "findFacetsLoopFromSegment2Segment currently supports only 3D");
// get the point el corresponding to the central node
CSR<Element> points_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, points_to_nodes, 0);
auto && points_to_node = points_to_nodes.getRow(cent_node);
auto point_el = *points_to_node.begin();
auto & segments_to_point = mesh_facets.getElementToSubelement(point_el);
AKANTU_DEBUG_ASSERT(point_el.type == _point_1,
"Provided node element type is wrong");
for (UInt i = 0; i < 2; i++) {
// check the dimensions
AKANTU_DEBUG_ASSERT(
Mesh::getSpatialDimension(limit_facets(i).type) == dim - 1,
"Facet" << limit_facets(i) << " has wrong spatial dimension");
AKANTU_DEBUG_ASSERT(
Mesh::getSpatialDimension(limit_segments(i).type) == dim - 2,
"Segment" << limit_segments(i) << " has wrong spatial dimension");
// check if the provided node is shared by two segments
auto ret = std::find(segments_to_point.begin(), segments_to_point.end(),
limit_segments(i));
AKANTU_DEBUG_ASSERT(ret != segments_to_point.end(),
"Segment " << limit_segments(i)
<< " doesn't contain the central node");
// check if limit facets contain limit segments
auto & facets_to_segment =
mesh_facets.getElementToSubelement(limit_segments(i));
auto ret1 = std::find(facets_to_segment.begin(), facets_to_segment.end(),
limit_facets(i));
AKANTU_DEBUG_ASSERT(ret1 != facets_to_segment.end(),
"Facet " << limit_facets(i)
<< " doesn't contain the segment "
<< limit_segments(i));
}
Array<Element> facets_in_loop;
// Create a struct to hold properties for each vertex
typedef struct vertex_properties {
Element segment;
} vertex_properties_t;
// Create a struct to hold properties for each edge
typedef struct edge_properties {
Element facet;
Real weight;
} edge_properties_t;
// Define the type of the graph
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
vertex_properties_t, edge_properties_t>
graph_t;
typedef typename graph_t::vertex_descriptor vertex_descriptor_t;
typedef typename graph_t::edge_descriptor edge_descriptor_t;
graph_t g;
// prepare the list of facets sharing the central node
CSR<Element> facets_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, facets_to_nodes, dim - 1);
auto && facets_to_node = facets_to_nodes.getRow(cent_node);
std::set<Element> facets_added;
std::map<Element, vertex_descriptor_t> segment_vertex_map;
// add starting and ending segment to the graph
vertex_descriptor_t v_start = boost::add_vertex(g);
g[v_start].segment = limit_segments(0);
vertex_descriptor_t v_end = boost::add_vertex(g);
g[v_end].segment = limit_segments(1);
segment_vertex_map[limit_segments(0)] = v_start;
segment_vertex_map[limit_segments(1)] = v_end;
for (auto && facet : facets_to_node) {
// discard undesired facets first
if (facet == limit_facets(0) or facet == limit_facets(1))
continue;
if (not isFacetAndNodesGood(facet))
continue;
if (belong2SameElement(limit_facets(0), facet) or
belong2SameElement(limit_facets(1), facet))
continue;
// check the effective stress on this facet
auto & facet_material_index =
coh_model.getFacetMaterial(facet.type, facet.ghost_type)(facet.element);
auto & mat = model.getMaterial(facet_material_index);
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
if (mat_coh == nullptr)
continue;
auto && mat_facet_filter =
mat_coh->getFacetFilter(facet.type, facet.ghost_type);
UInt facet_local_num = mat_facet_filter.find(facet.element);
AKANTU_DEBUG_ASSERT(facet_local_num != UInt(-1),
"Local facet number was not identified");
if (not mat_coh->isInternal<Real>("effective_stresses", _ek_regular))
continue;
auto & eff_stress_array = mat.getInternal<Real>("effective_stresses")(
facet.type, facet.ghost_type);
// eff stress is always non-negative
auto eff_stress = eff_stress_array(facet_local_num);
if (eff_stress == 0)
eff_stress = 1e-3;
// if (eff_stress < 1)
// continue;
// identify 2 sides of a facets
Array<Element> side_segments;
auto && facet_segments = mesh_facets.getSubelementToElement(facet);
for (auto & segment : facet_segments) {
auto ret = std::find(segments_to_point.begin(), segments_to_point.end(),
segment);
if (ret != segments_to_point.end()) {
side_segments.push_back(segment);
}
}
AKANTU_DEBUG_ASSERT(side_segments.size() == 2,
"Number of side facets is wrong");
// add corresponding vertex (if not there)and edge into graph
Array<vertex_descriptor_t> v(2);
for (UInt i = 0; i < 2; i++) {
auto it = segment_vertex_map.find(side_segments(i));
if (it != segment_vertex_map.end()) {
v(i) = it->second;
} else {
v(i) = boost::add_vertex(g);
g[v(i)].segment = side_segments(i);
segment_vertex_map[side_segments(i)] = v(i);
}
}
// add corresponding edge into the graph
auto ret = facets_added.emplace(facet);
if (ret.second) {
// compute facet's area to use as a weight
// auto facet_area = MeshUtils::getFacetArea(model, facet);
// add edge
std::pair<edge_descriptor_t, bool> e = boost::add_edge(v(0), v(1), g);
// g[e.first].weight = facet_area;
g[e.first].weight = 1 / eff_stress;
g[e.first].facet = facet;
}
}
// BGL Dijkstra's Shortest Paths here...
std::vector<Real> distances(boost::num_vertices(g));
std::vector<vertex_descriptor_t> predecessors(boost::num_vertices(g));
boost::dijkstra_shortest_paths(
g, v_start,
boost::weight_map(boost::get(&edge_properties_t::weight, g))
.distance_map(boost::make_iterator_property_map(
distances.begin(), boost::get(boost::vertex_index, g)))
.predecessor_map(boost::make_iterator_property_map(
predecessors.begin(), boost::get(boost::vertex_index, g))));
// Extract the shortest path from v_end to v_start (reversed order)
typedef std::vector<edge_descriptor_t> path_t;
path_t path;
vertex_descriptor_t v = v_end;
for (vertex_descriptor_t u = predecessors[v]; u != v;
v = u, u = predecessors[v]) {
std::pair<edge_descriptor_t, bool> edge_pair = boost::edge(u, v, g);
path.push_back(edge_pair.first);
}
// compute average effective stress over the loop and discard if <1
Array<Element> facet_loop_tmp;
for (auto edge : path) {
facet_loop_tmp.push_back(g[edge].facet);
}
auto av_eff_stress = averageEffectiveStressInMultipleFacets(facet_loop_tmp);
if (av_eff_stress < 1)
return facets_in_loop;
// check path for smoothness
bool recompute_path{false};
do {
recompute_path = false;
if (path.size()) {
for (UInt i = 0; i <= path.size(); i++) {
// evaluate two neighboring facets
Element facet1, facet2;
if (i == 0) {
facet1 = limit_facets(1);
facet2 = g[path[i]].facet;
} else if (i == path.size()) {
facet1 = g[path[i - 1]].facet;
facet2 = limit_facets(0);
} else {
facet1 = g[path[i - 1]].facet;
facet2 = g[path[i]].facet;
}
// discard short distances
auto facet1_indiam =
MeshUtils::getInscribedCircleDiameter(model, facet1);
auto facet2_indiam =
MeshUtils::getInscribedCircleDiameter(model, facet2);
auto hypotenuse = sqrt(facet1_indiam * facet1_indiam +
facet2_indiam * facet2_indiam) /
2;
auto dist = MeshUtils::distanceBetweenIncentersCorrected(
mesh_facets, facet1, facet2);
// get abs of dot product between two normals
Real dot =
MeshUtils::cosSharpAngleBetween2Facets(model, facet1, facet2);
if (dist < hypotenuse or dot < min_dot) {
if (i < path.size()) {
boost::remove_edge(path[i], g);
} else {
boost::remove_edge(path[i - 1], g);
}
recompute_path = true;
break;
}
}
// find new shortest path without problematic edge
if (recompute_path) {
boost::dijkstra_shortest_paths(
g, v_start,
boost::weight_map(boost::get(&edge_properties_t::weight, g))
.distance_map(boost::make_iterator_property_map(
distances.begin(), boost::get(boost::vertex_index, g)))
.predecessor_map(boost::make_iterator_property_map(
predecessors.begin(), boost::get(boost::vertex_index, g))));
path.clear();
v = v_end;
for (vertex_descriptor_t u = predecessors[v]; u != v;
v = u, u = predecessors[v]) {
std::pair<edge_descriptor_t, bool> edge_pair = boost::edge(u, v, g);
path.push_back(edge_pair.first);
}
}
}
} while (recompute_path);
// add the shortest path facets
for (typename path_t::reverse_iterator riter = path.rbegin();
riter != path.rend(); ++riter) {
vertex_descriptor_t u_tmp = boost::source(*riter, g);
vertex_descriptor_t v_tmp = boost::target(*riter, g);
edge_descriptor_t e_tmp = boost::edge(u_tmp, v_tmp, g).first;
facets_in_loop.push_back(g[e_tmp].facet);
}
return facets_in_loop;
}
/* ------------------------------------------------------------------- */
Array<Element>
ASRTools::findSingleFacetLoop(const Array<Element> & limit_facets,
const Array<Element> & limit_segments,
const UInt & cent_node) {
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(limit_facets(0) != limit_facets(1),
"Limit facets are equal");
AKANTU_DEBUG_ASSERT(limit_segments(0) != limit_segments(1),
"Limit segments are equal");
AKANTU_DEBUG_ASSERT(
dim == 3, "findFacetsLoopFromSegment2Segment currently supports only 3D");
// get the point el corresponding to the central node
CSR<Element> points_to_nodes;
MeshUtils::buildNode2Elements(mesh_facets, points_to_nodes, 0);
auto && points_to_node = points_to_nodes.getRow(cent_node);
auto point_el = *points_to_node.begin();
auto & segments_to_node = mesh_facets.getElementToSubelement(point_el);
AKANTU_DEBUG_ASSERT(point_el.type == _point_1,
"Provided node element type is wrong");
for (UInt i = 0; i < 2; i++) {
// check the dimensions
AKANTU_DEBUG_ASSERT(
Mesh::getSpatialDimension(limit_facets(i).type) == dim - 1,
"Facet" << limit_facets(i) << " has wrong spatial dimension");
AKANTU_DEBUG_ASSERT(
Mesh::getSpatialDimension(limit_segments(i).type) == dim - 2,
"Segment" << limit_segments(i) << " has wrong spatial dimension");
// check if the provided node is shared by two segments
auto ret = std::find(segments_to_node.begin(), segments_to_node.end(),
limit_segments(i));
AKANTU_DEBUG_ASSERT(ret != segments_to_node.end(),
"Segment " << limit_segments(i)
<< " doesn't contain the central node");
// check if limit facets contain limit segments
auto & facets_to_segment =
mesh_facets.getElementToSubelement(limit_segments(i));
auto ret1 = std::find(facets_to_segment.begin(), facets_to_segment.end(),
limit_facets(i));
AKANTU_DEBUG_ASSERT(ret1 != facets_to_segment.end(),
"Facet " << limit_facets(i)
<< " doesn't contain the segment "
<< limit_segments(i));
}
Array<Element> facets_in_loop;
// check if two segments are not connected by a single facet
auto st_segment_neighbors =
mesh_facets.getElementToSubelement(limit_segments(0));
auto end_segment_neighbors =
mesh_facets.getElementToSubelement(limit_segments(1));
std::sort(st_segment_neighbors.begin(), st_segment_neighbors.end());
std::sort(end_segment_neighbors.begin(), end_segment_neighbors.end());
Array<Element> shared_facets(st_segment_neighbors.size());
// An iterator to the end of the constructed range.
auto it = std::set_intersection(
st_segment_neighbors.begin(), st_segment_neighbors.end(),
end_segment_neighbors.begin(), end_segment_neighbors.end(),
shared_facets.begin());
shared_facets.resize(it - shared_facets.begin());
// if there is a single facet connecting two segments test it
if (shared_facets.size() == 1) {
bool bad_facet{false};
if (not isFacetAndNodesGood(shared_facets(0)))
bad_facet = true;
// check angle with starting and ending -> not to be sharp
bool sharp_angle{false};
auto facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, shared_facets(0));
for (auto && limit_facet : limit_facets) {
auto limit_facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, limit_facet);
auto hypotenuse = sqrt(limit_facet_indiam * limit_facet_indiam +
facet_indiam * facet_indiam) /
2;
auto dist = MeshUtils::distanceBetweenIncentersCorrected(
mesh_facets, limit_facet, shared_facets(0));
if (dist <= hypotenuse) {
sharp_angle = true;
break;
}
}
if (not sharp_angle and not bad_facet) {
facets_in_loop.push_back(shared_facets(0));
}
}
return facets_in_loop;
}
/* ------------------------------------------------------------------- */
bool ASRTools::isFacetAndNodesGood(const Element & facet, UInt material_id,
bool check_asr_nodes) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto facet_type = facet.type;
auto gt = facet.ghost_type;
auto & mesh_facets = inserter.getMeshFacets();
Vector<UInt> facet_nodes = mesh_facets.getConnectivity(facet);
auto & check_facets = inserter.getCheckFacets(facet_type, gt);
// check if the facet is not ghost
if (gt == _ghost)
return false;
// check if the facet is allowed to be inserted
if (check_facets(facet.element) == false)
return false;
for (auto & facet_node : facet_nodes) {
// check if the facet's nodes are not pure ghost nodes
if (model.getMesh().isPureGhostNode(facet_node))
return false;
// check if the facet's nodes are asr nodes
if (check_asr_nodes and this->ASR_nodes(facet_node))
return false;
}
// check if the facet material is good
if (material_id != UInt(-1)) {
const auto & facet_material =
coh_model.getFacetMaterial(facet_type, gt)(facet.element);
if (facet_material != material_id)
return false;
}
return true;
}
/* ------------------------------------------------------------------- */
bool ASRTools::belong2SameElement(const Element & facet1,
const Element & facet2) {
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
Array<Element> f1_neighbors, f2_neighbors;
auto facet1_neighbors = mesh_facets.getElementToSubelement(facet1);
for (auto && neighbor : facet1_neighbors) {
if (mesh.getKind(neighbor.type) == _ek_regular)
f1_neighbors.push_back(neighbor);
if (mesh.getKind(neighbor.type) == _ek_cohesive) {
auto && coh_neighbors = mesh_facets.getSubelementToElement(neighbor);
for (auto && coh_neighbor : coh_neighbors) {
if (coh_neighbor == facet1)
continue;
auto coh_facet_neighbors =
mesh_facets.getElementToSubelement(coh_neighbor);
for (auto && coh_facet_neighbor : coh_facet_neighbors) {
if (mesh.getKind(coh_facet_neighbor.type) == _ek_regular)
f1_neighbors.push_back(coh_facet_neighbor);
}
}
}
}
auto facet2_neighbors = mesh_facets.getElementToSubelement(facet2);
for (auto && neighbor : facet2_neighbors) {
if (mesh.getKind(neighbor.type) == _ek_regular)
f2_neighbors.push_back(neighbor);
if (mesh.getKind(neighbor.type) == _ek_cohesive) {
auto && coh_neighbors = mesh_facets.getSubelementToElement(neighbor);
for (auto && coh_neighbor : coh_neighbors) {
if (coh_neighbor == facet2)
continue;
auto coh_facet_neighbors =
mesh_facets.getElementToSubelement(coh_neighbor);
for (auto && coh_facet_neighbor : coh_facet_neighbors) {
if (mesh.getKind(coh_facet_neighbor.type) == _ek_regular)
f2_neighbors.push_back(coh_facet_neighbor);
}
}
}
}
std::sort(f1_neighbors.begin(), f1_neighbors.end());
std::sort(f2_neighbors.begin(), f2_neighbors.end());
Array<Element> shared_neighbors(f1_neighbors.size());
// An iterator to the end of the constructed range.
auto it = std::set_intersection(f1_neighbors.begin(), f1_neighbors.end(),
f2_neighbors.begin(), f2_neighbors.end(),
shared_neighbors.begin());
shared_neighbors.resize(it - shared_neighbors.begin());
if (shared_neighbors.size() == 0)
return false;
// check kind of shared neighbor
auto shared_neighbor = shared_neighbors(0);
if (mesh.getKind(shared_neighbor.type) != _ek_regular)
return false;
return true;
}
/* ------------------------------------------------------------------- */
bool ASRTools::isNodeWithinMaterial(Element & node, UInt material_id) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = coh_model.getSpatialDimension();
CSR<Element> nodes_to_facets;
MeshUtils::buildNode2Elements(mesh_facets, nodes_to_facets, dim - 1);
for (auto & facet : nodes_to_facets.getRow(node.element)) {
auto & facet_material =
coh_model.getFacetMaterial(facet.type, facet.ghost_type)(facet.element);
if (facet_material != material_id)
return false;
}
return true;
}
/* ------------------------------------------------------------------- */
bool ASRTools::pickFacetNeighborsOld(Element & cent_facet) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = mesh.getSpatialDimension();
const auto & pos = mesh.getNodes();
const auto pos_it = make_view(pos, dim).begin();
auto & doubled_facets = mesh_facets.getElementGroup("doubled_facets");
auto & facet_conn =
mesh_facets.getConnectivity(cent_facet.type, cent_facet.ghost_type);
auto & cent_facet_material = coh_model.getFacetMaterial(
cent_facet.type, cent_facet.ghost_type)(cent_facet.element);
CSR<Element> nodes_to_segments;
MeshUtils::buildNode2Elements(mesh_facets, nodes_to_segments, dim - 1);
Array<Element> two_neighbors(2);
two_neighbors.set(ElementNull);
for (auto node : arange(2)) {
/// vector of the central facet
Vector<Real> cent_facet_dir(pos_it[facet_conn(cent_facet.element, !node)],
true);
cent_facet_dir -=
Vector<Real>(pos_it[facet_conn(cent_facet.element, node)]);
cent_facet_dir /= cent_facet_dir.norm();
// dot product less than -0.5 discards any < 120 deg
Real min_dot = -0.5;
// Real min_dot = std::numeric_limits<Real>::max();
Vector<Real> neighbor_facet_dir(dim);
for (auto & elem :
nodes_to_segments.getRow(facet_conn(cent_facet.element, node))) {
if (elem.element == cent_facet.element)
continue;
if (elem.type != cent_facet.type)
continue;
if (elem.ghost_type != cent_facet.ghost_type)
continue;
if (not inserter.getCheckFacets(elem.type, elem.ghost_type)(elem.element))
continue;
// discard neighbors from different materials
auto & candidate_facet_material =
coh_model.getFacetMaterial(elem.type, elem.ghost_type)(elem.element);
if (candidate_facet_material != cent_facet_material)
continue;
/// decide which node of the neighbor is the second
UInt first_node{facet_conn(cent_facet.element, node)};
UInt second_node(-1);
if (facet_conn(elem.element, 0) == first_node) {
second_node = facet_conn(elem.element, 1);
} else if (facet_conn(elem.element, 1) == first_node) {
second_node = facet_conn(elem.element, 0);
} else
AKANTU_EXCEPTION(
"Neighboring facet"
<< elem << " with nodes " << facet_conn(elem.element, 0) << " and "
<< facet_conn(elem.element, 1)
<< " doesn't have node in common with the central facet "
<< cent_facet << " with nodes " << facet_conn(cent_facet.element, 0)
<< " and " << facet_conn(cent_facet.element, 1));
/// discard facets intersecting other ASR elements
if (this->ASR_nodes(second_node))
continue;
neighbor_facet_dir = pos_it[second_node];
neighbor_facet_dir -= Vector<Real>(pos_it[first_node]);
neighbor_facet_dir /= neighbor_facet_dir.norm();
Real dot = cent_facet_dir.dot(neighbor_facet_dir);
if (dot < min_dot) {
min_dot = dot;
two_neighbors(node) = elem;
}
}
}
// insert neighbors only if two of them were identified
if (two_neighbors.find(ElementNull) == UInt(-1)) {
for (auto & neighbor : two_neighbors) {
doubled_facets.add(neighbor);
for (UInt node : arange(2)) {
this->ASR_nodes(facet_conn(neighbor.element, node)) = true;
}
}
return true;
} else
return false;
}
/* ----------------------------------------------------------------------- */
bool ASRTools::pickFacetNeighbors(Element & cent_facet) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = mesh.getSpatialDimension();
auto facet_type = cent_facet.type;
auto facet_gt = cent_facet.ghost_type;
auto facet_nb = cent_facet.element;
auto & doubled_facets = mesh_facets.getElementGroup("doubled_facets");
auto & doubled_nodes = mesh.getNodeGroup("doubled_nodes");
auto & facet_conn = mesh_facets.getConnectivity(facet_type, facet_gt);
auto & facet_material_index =
coh_model.getFacetMaterial(facet_type, facet_gt)(facet_nb);
// get list of the subel connected to the facet (nodes in 2D, segments
// in 3D)
const Vector<Element> & subelements_to_element =
mesh_facets.getSubelementToElement(cent_facet);
Array<Element> neighbors(subelements_to_element.size());
neighbors.set(ElementNull);
// max weight parameter computed for each subelement iteration
// here this parameter = dot product between two normals
// minimum 60 deg between normals -> 120 between dips
Real weight_parameter_threshold(0.5);
std::vector<Real> max_weight_parameters(subelements_to_element.size(),
weight_parameter_threshold);
// identify a facet's neighbor through each subelement
for (UInt i : arange(subelements_to_element.size())) {
auto & subel = subelements_to_element(i);
auto & connected_elements = mesh_facets.getElementToSubelement(
subel.type, subel.ghost_type)(subel.element);
for (auto & connected_element : connected_elements) {
// check all possible unsatisfactory conditions
if (connected_element.type != facet_type)
continue;
if (connected_element.element == facet_nb)
continue;
auto & candidate_facet_material_index = coh_model.getFacetMaterial(
connected_element.type,
connected_element.ghost_type)(connected_element.element);
if (candidate_facet_material_index != facet_material_index)
continue;
if (not inserter.getCheckFacets(connected_element.type,
connected_element.ghost_type)(
connected_element.element))
continue;
// discard facets intersecting other ASR elements
bool ASR_node{false};
for (UInt j : arange(facet_conn.getNbComponent())) {
auto node = facet_conn(connected_element.element, j);
if (this->ASR_nodes(node))
ASR_node = true;
}
if (ASR_node)
continue;
// get inscribed diameter
Real facet_indiam =
MeshUtils::getInscribedCircleDiameter(model, cent_facet);
// get distance between two barycenters
auto dist = MeshUtils::distanceBetweenIncentersCorrected(
mesh_facets, cent_facet, connected_element);
// ad-hoc rule on barycenters spacing
// it should discard all elements under sharp angle
if (dist < facet_indiam)
continue;
// get abs of dot product between two normals
Real dot = MeshUtils::cosSharpAngleBetween2Facets(model, cent_facet,
connected_element);
auto weight_parameter = dot;
if (weight_parameter > max_weight_parameters[i]) {
max_weight_parameters[i] = weight_parameter;
neighbors(i) = connected_element;
}
}
}
// different insertion procedures for 2D and 3D cases
switch (dim) {
case 2: {
if (neighbors.find(ElementNull) == UInt(-1)) {
for (auto & neighbor : neighbors) {
doubled_facets.add(neighbor);
for (UInt node : arange(2)) {
this->ASR_nodes(facet_conn(neighbor.element, node)) = true;
}
}
return true;
} else
return false;
}
case 3: {
auto max_el_pos = std::max_element(max_weight_parameters.begin(),
max_weight_parameters.end());
if (*max_el_pos > weight_parameter_threshold) {
auto max_param_index =
std::distance(max_weight_parameters.begin(), max_el_pos);
auto & neighbor = neighbors(max_param_index);
doubled_facets.add(neighbor);
for (UInt node : arange(facet_conn.getNbComponent())) {
doubled_nodes.add(facet_conn(neighbor.element, node));
this->ASR_nodes(facet_conn(neighbor.element, node)) = true;
}
return true;
} else
return false;
}
default:
AKANTU_EXCEPTION("Provided dimension is not supported");
}
}
/* ------------------------------------------------------------------ */
void ASRTools::preventCohesiveInsertionInNeighbors() {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto el_type = *mesh.elementTypes(dim, gt, _ek_regular).begin();
auto facet_type = Mesh::getFacetType(el_type);
// auto subfacet_type = Mesh::getFacetType(facet_type);
// auto & facet_conn = mesh.getConnectivity(facet_type, gt);
// auto facet_conn_it = facet_conn.begin(facet_conn.getNbComponent());
auto & subfacets_to_facets =
mesh_facets.getSubelementToElement(facet_type, gt);
auto nb_subfacet = subfacets_to_facets.getNbComponent();
auto subf_to_fac_it = subfacets_to_facets.begin(nb_subfacet);
// auto & doubled_nodes = mesh.getNodeGroup("doubled_nodes");
// CSR<Element> nodes_to_elements;
// MeshUtils::buildNode2Elements(mesh_facets, nodes_to_elements, dim - 1);
// for (auto node : doubled_nodes.getNodes()) {
// for (auto & elem : nodes_to_elements.getRow(node)) {
// if (elem.type != facet_type)
// continue;
// inserter.getCheckFacets(elem.type, gt)(elem.element) = false;
// }
// }
auto & el_group = mesh_facets.getElementGroup("doubled_facets");
Array<UInt> element_ids = el_group.getElements(facet_type);
for (UInt i : arange(element_ids.size() / 2)) {
auto facet1 = element_ids(i);
auto facet2 = element_ids(i + element_ids.size() / 2);
std::vector<Element> subfacets1(nb_subfacet);
std::vector<Element> subfacets2(nb_subfacet);
for (UInt i : arange(nb_subfacet)) {
subfacets1[i] = subf_to_fac_it[facet1](i);
subfacets2[i] = subf_to_fac_it[facet2](i);
}
std::sort(subfacets1.begin(), subfacets1.end());
std::sort(subfacets2.begin(), subfacets2.end());
std::vector<Element> dif_subfacets(2 * nb_subfacet);
std::vector<Element>::iterator it;
// identify subfacets not shared by two facets
it = std::set_difference(subfacets1.begin(), subfacets1.end(),
subfacets2.begin(), subfacets2.end(),
dif_subfacets.begin());
dif_subfacets.resize(it - dif_subfacets.begin());
// prevent insertion of cohesives in the facets including these subf
for (auto & subfacet : dif_subfacets) {
auto neighbor_facets = mesh_facets.getElementToSubelement(subfacet);
for (auto & neighbor_facet : neighbor_facets) {
inserter.getCheckFacets(facet_type, gt)(neighbor_facet.element) = false;
}
}
}
}
/* ------------------------------------------------------------------- */
void ASRTools::insertOppositeFacetsAndCohesives() {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & insertion = inserter.getInsertionFacetsByElement();
auto & mesh = model.getMesh();
auto & mesh_facets = inserter.getMeshFacets();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
const auto & pos = mesh.getNodes();
const auto pos_it = make_view(pos, dim).begin();
auto & doubled_facets = mesh_facets.getElementGroup("doubled_facets");
/// sort facet numbers in doubled_facets_group to comply with new_elements
/// event passed by the inserter
doubled_facets.optimize();
/// instruct the inserter which facets to duplicate
for (auto & type : doubled_facets.elementTypes(dim - 1)) {
const auto element_ids = doubled_facets.getElements(type, gt);
/// iterate over facets to duplicate
for (auto && el : element_ids) {
inserter.getCheckFacets(type, gt)(el) = false;
Element new_facet{type, el, gt};
insertion(new_facet) = true;
}
}
/// duplicate facets and insert coh els
inserter.insertElements(false);
/// add facets connectivity to the mesh and the element group
NewElementsEvent new_facets_event;
for (auto & type : doubled_facets.elementTypes(dim - 1)) {
const auto element_ids = doubled_facets.getElements(type, gt);
if (not mesh.getConnectivities().exists(type, gt))
mesh.addConnectivityType(type, gt);
auto & facet_conn = mesh.getConnectivity(type, gt);
auto & mesh_facet_conn = mesh_facets.getConnectivity(type, gt);
const UInt nb_nodes_facet = facet_conn.getNbComponent();
const auto mesh_facet_conn_it =
make_view(mesh_facet_conn, nb_nodes_facet).begin();
/// iterate over duplicated facets
for (auto && el : element_ids) {
Vector<UInt> facet_nodes = mesh_facet_conn_it[el];
facet_conn.push_back(facet_nodes);
Element new_facet{type, facet_conn.size() - 1, gt};
new_facets_event.getList().push_back(new_facet);
}
}
MeshUtils::fillElementToSubElementsData(mesh);
mesh.sendEvent(new_facets_event);
// fill up ASR facets vector
this->ASR_facets_from_mesh.resize(this->asr_facets.size());
for (UInt i = 0; i != this->asr_facets.size(); i++) {
auto single_site_facets = this->asr_facets(i);
for (auto & facet : single_site_facets) {
Element cohesive{ElementNull};
auto & connected_els = mesh_facets.getElementToSubelement(facet);
for (auto & connected_el : connected_els) {
if (mesh.getKind(connected_el.type) == _ek_cohesive) {
cohesive = connected_el;
break;
}
}
AKANTU_DEBUG_ASSERT(cohesive != ElementNull,
"Connected cohesive element not identified");
auto && connected_subels = mesh.getSubelementToElement(cohesive);
for (auto & connected_subel : connected_subels) {
if (connected_subel.type != facet.type)
continue;
this->ASR_facets_from_mesh(i).push_back(connected_subel);
}
}
}
// create an element group with nodes to apply Dirichlet
model.getMesh().createElementGroupFromNodeGroup("doubled_nodes",
"doubled_nodes", dim - 1);
// update FEEngineBoundary with new elements
model.getFEEngineBoundary().initShapeFunctions(_not_ghost);
model.getFEEngineBoundary().initShapeFunctions(_ghost);
model.getFEEngineBoundary().computeNormalsOnIntegrationPoints(_not_ghost);
model.getFEEngineBoundary().computeNormalsOnIntegrationPoints(_ghost);
}
/* ----------------------------------------------------------------------- */
void ASRTools::assignCrackNumbers() {
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
for (auto && type_facet : mesh_facets.elementTypes(dim - 1)) {
ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet);
auto & crack_numbers =
mesh.getDataPointer<UInt>("crack_numbers", type_cohesive);
auto & coh_conn = mesh.getConnectivity(type_cohesive, gt);
auto nb_coh_nodes = coh_conn.getNbComponent();
auto coh_conn_it = coh_conn.begin(coh_conn.getNbComponent());
// initialize a graph
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>
Graph;
Graph graph;
// build the graph based on the connectivity of cohesive elements
for (UInt i = 0; i < coh_conn.size(); i++) {
for (UInt j = i + 1; j < coh_conn.size(); j++) {
auto nodes_1 = coh_conn_it[i];
auto nodes_2 = coh_conn_it[j];
std::vector<UInt> nod_1(nb_coh_nodes);
std::vector<UInt> nod_2(nb_coh_nodes);
for (UInt k : arange(nb_coh_nodes)) {
nod_1[k] = nodes_1(k);
nod_2[k] = nodes_2(k);
}
std::sort(nod_1.begin(), nod_1.end());
std::sort(nod_2.begin(), nod_2.end());
std::vector<UInt> common_nodes(nb_coh_nodes);
std::vector<UInt>::iterator it;
// An iterator to the end of the constructed range.
it = std::set_intersection(nod_1.begin(), nod_1.end(), nod_2.begin(),
nod_2.end(), common_nodes.begin());
common_nodes.resize(it - common_nodes.begin());
// switch (dim) {
// case 2: {
// // 1 common node between 2 segments
// if (common_nodes.size() == 1) {
// boost::add_edge(i, j, graph);
// }
// break;
// }
// case 3: {
// 2 or 3 common nodes between 2 triangles
if (common_nodes.size() > 1) {
boost::add_edge(i, j, graph);
}
// break;
// }
// }
}
}
/// connectivity and number of components of a graph
std::vector<int> component(boost::num_vertices(graph));
int num = boost::connected_components(graph, &component[0]);
/// shift the crack numbers by the number of cracks on processors with the
/// lower rank
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.exclusiveScan(num);
for (auto & component_nb : component) {
component_nb += num;
}
/// assign a corresponding crack flag
for (UInt coh_el : arange(component.size())) {
crack_numbers(coh_el) = component[coh_el];
}
}
}
/* ------------------------------------------------------------------- */
void ASRTools::insertGap(const Real gap_ratio) {
AKANTU_DEBUG_IN();
if (gap_ratio == 0)
return;
auto & mesh = model.getMesh();
MeshAccessor mesh_accessor(mesh);
auto & pos2modify = mesh_accessor.getNodes();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto & el_group = mesh.getElementGroup("doubled_nodes");
auto & pos = mesh.getNodes();
auto pos_it = make_view(pos, dim).begin();
auto pos2modify_it = make_view(pos2modify, dim).begin();
for (auto & type : el_group.elementTypes(dim - 1)) {
auto & facet_conn = mesh.getConnectivity(type, gt);
const UInt nb_nodes_facet = facet_conn.getNbComponent();
auto facet_nodes_it = make_view(facet_conn, nb_nodes_facet).begin();
const auto element_ids = el_group.getElements(type, gt);
auto && fe_engine = model.getFEEngineBoundary();
auto nb_qpoints_per_facet = fe_engine.getNbIntegrationPoints(type, gt);
const auto & normals_on_quad =
fe_engine.getNormalsOnIntegrationPoints(type, gt);
auto normals_it = make_view(normals_on_quad, dim).begin();
for (UInt i : arange(element_ids.size())) {
auto el_id = element_ids(i);
Vector<Real> normal = normals_it[el_id * nb_qpoints_per_facet];
if (i < element_ids.size() / 2)
normal *= -1;
/// compute segment length
auto facet_nodes = facet_nodes_it[el_id];
UInt A, B;
A = facet_nodes(0);
B = facet_nodes(1);
Vector<Real> AB = Vector<Real>(pos_it[B]) - Vector<Real>(pos_it[A]);
Real correction = AB.norm() * gap_ratio / 2;
Vector<Real> half_opening_vector = normal * correction;
for (auto j : arange(nb_nodes_facet)) {
Vector<Real> node_pos(pos2modify_it[facet_nodes(j)]);
node_pos += half_opening_vector;
this->modified_pos(facet_nodes(j)) = true;
}
}
}
/// update FEEngine & FEEngineBoundary with new elements
model.getFEEngine().initShapeFunctions(_not_ghost);
model.getFEEngine().initShapeFunctions(_ghost);
model.getFEEngineBoundary().initShapeFunctions(_not_ghost);
model.getFEEngineBoundary().initShapeFunctions(_ghost);
model.getFEEngineBoundary().computeNormalsOnIntegrationPoints(_not_ghost);
model.getFEEngineBoundary().computeNormalsOnIntegrationPoints(_ghost);
AKANTU_DEBUG_OUT();
}
/* ------------------------------------------------------------------- */
void ASRTools::insertGap3D(const Real gap_ratio) {
AKANTU_DEBUG_IN();
if (gap_ratio == 0)
return;
auto & mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
MeshAccessor mesh_accessor(mesh);
auto & pos2modify = mesh_accessor.getNodes();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto & el_group = mesh_facets.getElementGroup("doubled_facets");
auto & pos = mesh.getNodes();
auto pos_it = make_view(pos, dim).begin();
auto pos2modify_it = make_view(pos2modify, dim).begin();
for (auto & type : el_group.elementTypes(dim - 1)) {
if ((dim == 3) and (type != _triangle_6))
AKANTU_EXCEPTION("The only facet type supported in 3D is _triangle_6");
const Array<UInt> element_ids = el_group.getElements(type, gt);
auto && fe_engine = model.getFEEngineBoundary();
auto nb_qpoints_per_facet = fe_engine.getNbIntegrationPoints(type, gt);
// identify pairs of facets
Array<UInt> facets_considered;
for (UInt i : arange(element_ids.size())) {
auto el_id = element_ids(i);
Element element{type, el_id, gt};
// if element was already considered -> skip
if (facets_considered.find(el_id) != UInt(-1))
continue;
Array<UInt> element_ids_half(element_ids.size() / 2);
UInt starting_pos;
if (i < element_ids.size() / 2) {
starting_pos = 0;
} else {
starting_pos = element_ids.size() / 2;
}
for (auto j : arange(element_ids_half.size())) {
element_ids_half(j) = element_ids(j + starting_pos);
}
// find a neighbor
const Vector<Element> & subelements_to_element =
mesh_facets.getSubelementToElement(element);
// identify a facet's neighbor through each subelement
Element neighbor(ElementNull);
Element border(ElementNull);
for (UInt i : arange(subelements_to_element.size())) {
auto & subel = subelements_to_element(i);
auto & connected_elements = mesh_facets.getElementToSubelement(subel);
for (auto & connected_element : connected_elements) {
// check all possible unsatisfactory conditions
if (connected_element.type != type)
continue;
if (connected_element.element == el_id)
continue;
// search for this neighbor in the doubled_nodes el group
UInt neighbor_pos_in_el_ids =
element_ids_half.find(connected_element.element);
if (neighbor_pos_in_el_ids == UInt(-1))
continue;
// if found -> subelement is the border
neighbor = connected_element;
border = subel;
facets_considered.push_back(el_id);
facets_considered.push_back(connected_element.element);
break;
}
if (neighbor != ElementNull)
break;
}
AKANTU_DEBUG_ASSERT(neighbor != ElementNull,
"Neighbor for the facet was not identified for the "
"purpose of the gap insertion");
// average the normal in between two neighbors
const auto & normals_on_quad =
fe_engine.getNormalsOnIntegrationPoints(type, gt);
auto normals_it = make_view(normals_on_quad, dim).begin();
Vector<Real> normal = normals_it[el_id * nb_qpoints_per_facet];
normal +=
Vector<Real>(normals_it[neighbor.element * nb_qpoints_per_facet]);
normal /= normal.norm();
// and correct it for the direction
if (i < element_ids.size() / 2) {
normal *= -1;
}
// compute segment length
AKANTU_DEBUG_ASSERT(
border.type == _segment_3,
"The only supported segment type in 3D is _segment_3");
auto & segment_conn =
mesh_facets.getConnectivity(border.type, border.ghost_type);
const UInt nb_nodes_segment = segment_conn.getNbComponent();
auto segment_nodes_it = make_view(segment_conn, nb_nodes_segment).begin();
auto segment_nodes = segment_nodes_it[border.element];
// 2 end nodes and the middle node
UInt A, B, middle_node;
A = segment_nodes(0);
B = segment_nodes(1);
middle_node = segment_nodes(2);
Vector<Real> AB = Vector<Real>(pos_it[B]) - Vector<Real>(pos_it[A]);
Real correction = AB.norm() * gap_ratio / 2;
Vector<Real> half_opening_vector = normal * correction;
Vector<Real> node_pos(pos2modify_it[middle_node]);
node_pos += half_opening_vector;
this->modified_pos(middle_node) = true;
}
}
/// update FEEngine & FEEngineBoundary with new elements
model.getFEEngine().initShapeFunctions(_not_ghost);
model.getFEEngine().initShapeFunctions(_ghost);
model.getFEEngineBoundary().initShapeFunctions(_not_ghost);
model.getFEEngineBoundary().initShapeFunctions(_ghost);
model.getFEEngineBoundary().computeNormalsOnIntegrationPoints(_not_ghost);
model.getFEEngineBoundary().computeNormalsOnIntegrationPoints(_ghost);
AKANTU_DEBUG_OUT();
}
/* ----------------------------------------------------------------------- */
// void ASRTools::onElementsAdded(const Array<Element> & elements,
// const NewElementsEvent &) {
// // function is activated only when expanding cohesive elements is on
// if (not this->cohesive_insertion)
// return;
// if (this->doubled_facets_ready) {
// return;
// }
// auto & mesh = model.getMesh();
// auto & mesh_facets = mesh.getMeshFacets();
// // auto & doubled_facets = mesh_facets.getElementGroup("doubled_facets");
// for (auto elements_range : akantu::MeshElementsByTypes(elements)) {
// auto type = elements_range.getType();
// auto ghost_type = elements_range.getGhostType();
// if (mesh.getKind(type) != _ek_regular)
// continue;
// if (ghost_type != _not_ghost)
// continue;
// /// add new facets into the doubled_facets group
// auto & element_ids = elements_range.getElements();
// for (auto && el : element_ids) {
// Element new_facet{type, el, ghost_type};
// doubled_facets.add(new_facet);
// }
// this->doubled_facets_ready = true;
// }
// }
/* --------------------------------------------------------------------------
*/
void ASRTools::onNodesAdded(const Array<UInt> & new_nodes,
const NewNodesEvent &) {
AKANTU_DEBUG_IN();
if (new_nodes.size() == 0)
return;
// increase the internal arrays by the number of new_nodes
UInt new_nb_nodes = this->modified_pos.size() + new_nodes.size();
this->modified_pos.resize(new_nb_nodes);
this->partition_border_nodes.resize(new_nb_nodes);
this->nodes_eff_stress.resize(new_nb_nodes);
this->ASR_nodes.resize(new_nb_nodes);
// function is activated only when expanding cohesive elements is on
if (not this->cohesive_insertion)
return;
if (this->asr_central_nodes_ready)
return;
auto & mesh = model.getMesh();
// auto & node_group = mesh.getNodeGroup("doubled_nodes");
// auto & central_nodes = node_group.getNodes();
auto pos_it = make_view(mesh.getNodes(), mesh.getSpatialDimension()).begin();
for (auto & new_node : new_nodes) {
const Vector<Real> & new_node_coord = pos_it[new_node];
auto central_nodes = this->asr_central_nodes;
for (auto & central_node : central_nodes) {
const Vector<Real> & central_node_coord = pos_it[central_node];
if (new_node_coord == central_node_coord) {
// node_group.add(new_node);
this->asr_central_nodes.push_back(new_node);
break;
}
}
}
this->asr_central_nodes_ready = true;
AKANTU_DEBUG_OUT();
}
/* ------------------------------------------------------------------------ */
void ASRTools::updateElementGroup(const std::string group_name) {
AKANTU_DEBUG_IN();
auto & mesh = model.getMesh();
AKANTU_DEBUG_ASSERT(mesh.elementGroupExists(group_name),
"Element group is not registered in the mesh");
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto && group = mesh.getElementGroup(group_name);
auto && pos = mesh.getNodes();
const auto pos_it = make_view(pos, dim).begin();
for (auto & type : group.elementTypes(dim - 1)) {
auto & facet_conn = mesh.getConnectivity(type, gt);
const UInt nb_nodes_facet = facet_conn.getNbComponent();
const auto facet_nodes_it = make_view(facet_conn, nb_nodes_facet).begin();
AKANTU_DEBUG_ASSERT(
type == _segment_2,
"Currently update group works only for el type _segment_2");
const auto element_ids = group.getElements(type, gt);
for (auto && el_id : element_ids) {
const auto connected_els = mesh.getElementToSubelement(type, gt)(el_id);
for (auto && connected_el : connected_els) {
auto type_solid = connected_el.type;
auto & solid_conn = mesh.getConnectivity(type_solid, gt);
const UInt nb_nodes_solid_el = solid_conn.getNbComponent();
const auto solid_nodes_it =
make_view(solid_conn, nb_nodes_solid_el).begin();
Vector<UInt> facet_nodes = facet_nodes_it[el_id];
Vector<UInt> solid_nodes = solid_nodes_it[connected_el.element];
// /// to which of connected elements facet belongs
// Array<UInt> solid_nodes(nb_nodes_solid_el);
// for (UInt node : arange(nb_nodes_solid_el)) {
// solid_nodes(node) = solid_nodes_it[connected_el.element](node);
// }
// /// check for the central facet node (id doesn't change nb)
// auto id = solid_nodes.find(facet_nodes(2));
// if (id == UInt(-1))
// continue;
/// check only the corner nodes of facets - central will not change
for (auto f : arange(2)) {
auto facet_node = facet_nodes(f);
const Vector<Real> & facet_node_coords = pos_it[facet_node];
for (auto s : arange(nb_nodes_solid_el)) {
auto solid_node = solid_nodes(s);
const Vector<Real> & solid_node_coords = pos_it[solid_node];
if (solid_node_coords == facet_node_coords) {
if (solid_node != facet_node) {
// group.removeNode(facet_node);
facet_conn(el_id, f) = solid_node;
// group.addNode(solid_node, true);
}
break;
}
}
}
}
}
}
group.optimize();
AKANTU_DEBUG_OUT();
}
/* -------------------------------------------------------------------------*/
// void ASRTools::applyDeltaU(Real delta_u) {
// // get element group with nodes to apply Dirichlet
// auto & crack_facets = model.getMesh().getElementGroup("doubled_nodes");
// DeltaU delta_u_bc(model, delta_u, getNodePairs());
// model.applyBC(delta_u_bc, crack_facets);
// }
/* --------------------------------------------------------------------------
*/
void ASRTools::applyGelStrain(const Matrix<Real> & prestrain) {
AKANTU_DEBUG_IN();
auto & mesh = model.getMesh();
auto dim = mesh.getSpatialDimension();
AKANTU_DEBUG_ASSERT(dim == 2, "This is 2D only!");
/// apply the new eigenstrain
for (auto element_type :
mesh.elementTypes(dim, _not_ghost, _ek_not_defined)) {
Array<Real> & prestrain_vect =
const_cast<Array<Real> &>(model.getMaterial("gel").getInternal<Real>(
"eigen_grad_u")(element_type));
auto prestrain_it = prestrain_vect.begin(dim, dim);
auto prestrain_end = prestrain_vect.end(dim, dim);
for (; prestrain_it != prestrain_end; ++prestrain_it)
(*prestrain_it) = prestrain;
}
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
void ASRTools::clearASREigenStrain() {
AKANTU_DEBUG_IN();
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
Matrix<Real> zero_eigenstrain(dim, dim, 0.);
GhostType gt = _not_ghost;
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
auto & prestrain_vect =
const_cast<Array<Real> &>(model.getMaterial("gel").getInternal<Real>(
"eigen_grad_u")(element_type));
auto prestrain_it = prestrain_vect.begin(dim, dim);
auto prestrain_end = prestrain_vect.end(dim, dim);
for (; prestrain_it != prestrain_end; ++prestrain_it)
(*prestrain_it) = zero_eigenstrain;
}
AKANTU_DEBUG_OUT();
}
/* --------------------------------------------------------------------------
*/
void ASRTools::storeASREigenStrain(Array<Real> & stored_eig) {
AKANTU_DEBUG_IN();
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
UInt nb_quads = 0;
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
const UInt nb_gp = model.getFEEngine().getNbIntegrationPoints(element_type);
nb_quads +=
model.getMaterial("gel").getElementFilter(element_type).size() * nb_gp;
}
stored_eig.resize(nb_quads);
auto stored_eig_it = stored_eig.begin(dim, dim);
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
auto & prestrain_vect =
const_cast<Array<Real> &>(model.getMaterial("gel").getInternal<Real>(
"eigen_grad_u")(element_type));
auto prestrain_it = prestrain_vect.begin(dim, dim);
auto prestrain_end = prestrain_vect.end(dim, dim);
for (; prestrain_it != prestrain_end; ++prestrain_it, ++stored_eig_it)
(*stored_eig_it) = (*prestrain_it);
}
AKANTU_DEBUG_OUT();
}
/* ------------------------------------------------------------------ */
void ASRTools::restoreASREigenStrain(Array<Real> & stored_eig) {
AKANTU_DEBUG_IN();
const auto & mesh = model.getMesh();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
auto stored_eig_it = stored_eig.begin(dim, dim);
for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
auto & prestrain_vect =
const_cast<Array<Real> &>(model.getMaterial("gel").getInternal<Real>(
"eigen_grad_u")(element_type));
auto prestrain_it = prestrain_vect.begin(dim, dim);
auto prestrain_end = prestrain_vect.end(dim, dim);
for (; prestrain_it != prestrain_end; ++prestrain_it, ++stored_eig_it)
(*prestrain_it) = (*stored_eig_it);
}
AKANTU_DEBUG_OUT();
}
// /* ------------------------------------------------------------------- */
// template <UInt dim> UInt ASRTools::insertCohesiveElementsOnContour() {
// AKANTU_DEBUG_IN();
// auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
// CohesiveElementInserter & inserter = coh_model.getElementInserter();
// if (not coh_model.getIsExtrinsic()) {
// AKANTU_EXCEPTION(
// "This function can only be used for extrinsic cohesive elements");
// }
// coh_model.interpolateStress();
// const Mesh & mesh_facets = coh_model.getMeshFacets();
// UInt nb_new_elements(0);
// auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
// // find crack topology within specific material and insert cohesives
// for (auto && mat : model.getMaterials()) {
// auto * mat_coh =
// dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
// if (mat_coh == nullptr)
// continue;
// auto data = mat_coh->determineCrackSurface();
// auto & contour_subfacets_coh_el = std::get<0>(data);
// auto & surface_subfacets_crack_nb = std::get<1>(data);
// auto & surface_nodes = std::get<2>(data);
// auto & contour_nodes = std::get<3>(data);
// if (not contour_subfacets_coh_el.size()) {
// continue;
// }
// std::map<UInt, UInt> facet_nbs_crack_nbs =
// mat_coh->findCriticalFacetsOnContour(contour_subfacets_coh_el,
// surface_subfacets_crack_nb,
// contour_nodes, surface_nodes);
// mat_coh->insertCohesiveElements(facet_nbs_crack_nbs, type_facet, false);
// }
// // insert the most stressed cohesive element
// nb_new_elements = inserter.insertElements();
// // communicate crack numbers
// communicateCrackNumbers();
// // // loop until no more holes are present
// // bool new_holes_filled{true};
// // while (new_holes_filled) {
// // new_holes_filled = false;
// // fill in holes
// for (auto && mat : model.getMaterials()) {
// auto * mat_coh =
// dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
// if (mat_coh == nullptr)
// continue;
// auto data = mat_coh->determineCrackSurface();
// auto & contour_subfacets_coh_el = std::get<0>(data);
// auto & surface_subfacets_crack_nb = std::get<1>(data);
// auto & surface_nodes = std::get<2>(data);
// // auto & contour_nodes = std::get<3>(data);
// if (not contour_subfacets_coh_el.size()) {
// continue;
// }
// std::map<UInt, UInt> facet_nbs_crack_nbs = mat_coh->findHolesOnContour(
// contour_subfacets_coh_el, surface_subfacets_crack_nb, surface_nodes);
// // new_holes_filled = facet_nbs_crack_nbs.size();
// // comm.allReduce(new_holes_filled, SynchronizerOperation::_lor);
// mat_coh->insertCohesiveElements(facet_nbs_crack_nbs, type_facet, false);
// }
// auto nb_new_holes = inserter.insertElements();
// nb_new_elements += nb_new_holes;
// // communicate crack numbers
// communicateCrackNumbers();
// // }
// AKANTU_DEBUG_OUT();
// return nb_new_elements;
// }
// template UInt ASRTools::insertCohesiveElementsOnContour<2>();
// template UInt ASRTools::insertCohesiveElementsOnContour<3>();
// /* ------------------------------------------------------------------- */
// template <UInt dim>
// UInt ASRTools::insertCohesiveElementsOnContourByNodes(
// Real av_stress_threshold) {
// AKANTU_DEBUG_IN();
// auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
// CohesiveElementInserter & inserter = coh_model.getElementInserter();
// if (not coh_model.getIsExtrinsic()) {
// AKANTU_EXCEPTION(
// "This function can only be used for extrinsic cohesive elements");
// }
// coh_model.interpolateStress();
// const Mesh & mesh_facets = coh_model.getMeshFacets();
// UInt nb_new_elements(0);
// auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
// // find global crack topology
// auto data = determineCrackSurface();
// auto & contour_subfacets_coh_el = std::get<0>(data);
// auto & surface_subfacets_crack_nb = std::get<1>(data);
// auto & surface_nodes = std::get<2>(data);
// auto & contour_nodes_subfacets = std::get<3>(data);
// // compute effective stress in all cohesive material linear sequent.
// for (auto && mat : model.getMaterials()) {
// auto * mat_coh =
// dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
// if (mat_coh == nullptr)
// continue;
// mat_coh->computeEffectiveStresses();
// }
// // identify facets on contour where cohesives should be inserted
// std::map<UInt, std::map<UInt, UInt>> mat_index_facet_nbs_crack_nbs =
// findCriticalFacetsOnContourByNodes(
// contour_subfacets_coh_el, surface_subfacets_crack_nb,
// contour_nodes_subfacets, surface_nodes, av_stress_threshold);
// // insert cohesives depending on a material
// for (auto & pair : mat_index_facet_nbs_crack_nbs) {
// auto mat_index = pair.first;
// auto & facet_nbs_crack_nbs = pair.second;
// auto & mat = model.getMaterial(mat_index);
// auto * mat_coh =
// dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
// if (mat_coh == nullptr)
// continue;
// mat_coh->insertCohesiveElements(facet_nbs_crack_nbs, type_facet, false);
// }
// // insert the most stressed cohesive element
// nb_new_elements = inserter.insertElements();
// // communicate crack numbers
// communicateCrackNumbers();
// AKANTU_DEBUG_OUT();
// return nb_new_elements;
// }
// template UInt
// ASRTools::insertCohesiveElementsOnContourByNodes<2>(Real
// av_stress_threshold); template UInt
// ASRTools::insertCohesiveElementsOnContourByNodes<3>(Real
// av_stress_threshold);
/* ------------------------------------------------------------------- */
template <UInt dim>
UInt ASRTools::insertLoopsOfStressedCohesives(Real min_dot) {
AKANTU_DEBUG_IN();
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
CohesiveElementInserter & inserter = coh_model.getElementInserter();
if (not coh_model.getIsExtrinsic()) {
AKANTU_EXCEPTION(
"This function can only be used for extrinsic cohesive elements");
}
coh_model.interpolateStress();
// compute effective stress in all cohesive material linear sequent.
for (auto && mat : model.getMaterials()) {
auto * mat_coh =
dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
if (mat_coh == nullptr)
continue;
mat_coh->computeEffectiveStresses();
}
auto && mesh = coh_model.getMesh();
const Mesh & mesh_facets = coh_model.getMeshFacets();
UInt nb_new_elements(0);
auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet);
auto & crack_numbers = mesh.getData<UInt>("crack_numbers", type_cohesive);
// find global crack topology
auto data = determineCrackSurface();
auto & contour_subfacets_coh_el = std::get<0>(data);
auto & surface_subfacets_crack_nb = std::get<1>(data);
auto & surface_nodes = std::get<2>(data);
auto & contour_nodes_subfacets = std::get<3>(data);
// identify facets on contour where cohesives should be inserted
std::map<UInt, std::map<UInt, UInt>> mat_index_facet_nbs_crack_nbs =
findStressedFacetsLoops(contour_subfacets_coh_el,
surface_subfacets_crack_nb,
contour_nodes_subfacets, surface_nodes, min_dot);
// insert cohesives depending on a material
std::map<UInt, UInt> facet_nbs_crack_nbs_global;
for (auto & pair : mat_index_facet_nbs_crack_nbs) {
auto mat_index = pair.first;
auto & facet_nbs_crack_nbs = pair.second;
auto & mat = model.getMaterial(mat_index);
auto * mat_coh =
dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
if (mat_coh == nullptr)
continue;
mat_coh->insertCohesiveElements(facet_nbs_crack_nbs, type_facet, false);
facet_nbs_crack_nbs_global.insert(facet_nbs_crack_nbs.begin(),
facet_nbs_crack_nbs.end());
}
// extend crack numbers array
for (auto && pair : facet_nbs_crack_nbs_global) {
auto && crack_nb = pair.second;
crack_numbers.push_back(crack_nb);
}
// insert the most stressed cohesive element
nb_new_elements = inserter.insertElements();
// communicate crack numbers
communicateCrackNumbers();
AKANTU_DEBUG_OUT();
return nb_new_elements;
}
template UInt ASRTools::insertLoopsOfStressedCohesives<2>(Real min_dot);
template UInt ASRTools::insertLoopsOfStressedCohesives<3>(Real min_dot);
/* ------------------------------------------------------------------- */
template <UInt dim> UInt ASRTools::insertStressedCohesives() {
AKANTU_DEBUG_IN();
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
CohesiveElementInserter & inserter = coh_model.getElementInserter();
if (not coh_model.getIsExtrinsic()) {
AKANTU_EXCEPTION(
"This function can only be used for extrinsic cohesive elements");
}
coh_model.interpolateStress();
auto && mesh = coh_model.getMesh();
const Mesh & mesh_facets = coh_model.getMeshFacets();
UInt nb_new_elements(0);
auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet);
auto & check_facets = inserter.getCheckFacets(type_facet);
auto & crack_numbers = mesh.getData<UInt>("crack_numbers", type_cohesive);
std::map<UInt, UInt> facet_nbs_crack_nbs;
std::set<UInt> facet_nbs;
// compute effective stress in all cohesive material linear sequent.
for (auto && mat : model.getMaterials()) {
auto * mat_coh =
dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
if (mat_coh == nullptr)
continue;
mat_coh->computeEffectiveStresses();
// loop on each facet of the material
auto && mat_facet_filter = mat_coh->getFacetFilter(type_facet);
for (auto && data : enumerate(mat_facet_filter)) {
auto facet_local_num = std::get<0>(data);
auto facet_global_num = std::get<1>(data);
if (check_facets(facet_global_num) == false)
continue;
// if (not mat_coh->isInternal<Real>("effective_stresses", _ek_regular))
// continue;
auto & eff_stress_array =
mat.getInternal<Real>("effective_stresses")(type_facet);
// eff stress is always non-negative
auto eff_stress = eff_stress_array(facet_local_num);
if (eff_stress >= 1) {
auto ret = facet_nbs.emplace(facet_global_num);
if (ret.second) {
facet_nbs_crack_nbs[facet_global_num] = 0;
}
}
}
mat_coh->insertCohesiveElements(facet_nbs_crack_nbs, type_facet, false);
}
// extend crack numbers array
for (auto && pair : facet_nbs_crack_nbs) {
auto && crack_nb = pair.second;
crack_numbers.push_back(crack_nb);
}
// insert the most stressed cohesive element
nb_new_elements = inserter.insertElements();
// communicate crack numbers
communicateCrackNumbers();
AKANTU_DEBUG_OUT();
return nb_new_elements;
}
template UInt ASRTools::insertStressedCohesives<2>();
template UInt ASRTools::insertStressedCohesives<3>();
// /* --------------------------------------------------------------- */
// std::map<UInt, std::map<UInt, UInt>>
// ASRTools::findCriticalFacetsOnContourByNodes(
// const std::map<Element, Element> & contour_subfacets_coh_el,
// const std::map<Element, UInt> & /*surface_subfacets_crack_nb*/,
// const std::map<UInt, std::set<Element>> & contour_nodes_subfacets,
// const std::set<UInt> & /*surface_nodes*/, Real av_stress_threshold) {
// AKANTU_DEBUG_IN();
// const Mesh & mesh = model.getMesh();
// const Mesh & mesh_facets = mesh.getMeshFacets();
// auto dim = mesh.getSpatialDimension();
// std::map<UInt, std::map<UInt, UInt>> mat_index_facet_nbs_crack_nbs;
// std::map<Element, Element> contour_to_single_facet_map;
// // TODO : make iteration on multiple facet types
// auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
// auto nb_facets = mesh.getNbElement(type_facet);
// // skip if no facets of this type are present
// if (not nb_facets) {
// return mat_index_facet_nbs_crack_nbs;
// }
// // create a copy to remove nodes where single facets were inserted
// auto contour_nodes_subfacets_copy = contour_nodes_subfacets;
// // first loop for single elements
// for (auto && pair : contour_nodes_subfacets) {
// auto cent_node = pair.first;
// auto subfacets = pair.second;
// if (subfacets.size() != 2) {
// std::cout << "Number of contour segments connected to the node "
// << cent_node << " is not equal to 2. Skipping" << std::endl;
// continue;
// }
// auto it = subfacets.begin();
// auto starting_segment(*it);
// std::advance(it, 1);
// auto ending_segment(*it);
// auto starting_coh_el = contour_subfacets_coh_el.at(starting_segment);
// auto ending_coh_el = contour_subfacets_coh_el.at(ending_segment);
// auto & crack_numbers = mesh.getData<UInt>(
// "crack_numbers", starting_coh_el.type, starting_coh_el.ghost_type);
// auto crack_nb = crack_numbers(starting_coh_el.element);
// auto starting_facet =
// mesh_facets.getSubelementToElement(starting_coh_el)(0);
// auto ending_facet = mesh_facets.getSubelementToElement(ending_coh_el)(0);
// // if an outstanding triangle element - skip
// if (starting_facet == ending_facet) {
// contour_nodes_subfacets_copy.erase(cent_node);
// continue;
// }
// Array<Element> limit_facets, limit_segments;
// limit_facets.push_back(starting_facet);
// limit_facets.push_back(ending_facet);
// limit_segments.push_back(starting_segment);
// limit_segments.push_back(ending_segment);
// auto single_facet_loop =
// findSingleFacetLoop(limit_facets, limit_segments, cent_node);
// if (not single_facet_loop.size())
// continue;
// // evaluate average effective stress over facets of the loop
// auto av_eff_stress =
// averageEffectiveStressInMultipleFacets(single_facet_loop);
// // if average effective stress exceeds threshold->decompose per mat
// if (av_eff_stress >= av_stress_threshold) {
// decomposeFacetLoopPerMaterial(single_facet_loop, crack_nb,
// mat_index_facet_nbs_crack_nbs);
// // update the map
// for (auto && limit_segment : limit_segments) {
// contour_to_single_facet_map[limit_segment] = single_facet_loop(0);
// }
// // remove node from the looping map
// contour_nodes_subfacets_copy.erase(cent_node);
// }
// }
// // second loop for long facet loops on a reduced map
// for (auto && pair : contour_nodes_subfacets_copy) {
// auto cent_node = pair.first;
// auto subfacets = pair.second;
// if (subfacets.size() != 2) {
// std::cout << "Number of contour segments connected to the node "
// << cent_node << " is not equal to 2. Skipping" << std::endl;
// continue;
// }
// auto it = subfacets.begin();
// auto starting_segment(*it);
// std::advance(it, 1);
// auto ending_segment(*it);
// auto starting_coh_el = contour_subfacets_coh_el.at(starting_segment);
// auto ending_coh_el = contour_subfacets_coh_el.at(ending_segment);
// auto & crack_numbers = mesh.getData<UInt>(
// "crack_numbers", starting_coh_el.type, starting_coh_el.ghost_type);
// auto crack_nb = crack_numbers(starting_coh_el.element);
// auto starting_facet =
// mesh_facets.getSubelementToElement(starting_coh_el)(0);
// auto ending_facet = mesh_facets.getSubelementToElement(ending_coh_el)(0);
// Array<Element> limit_facets, limit_segments;
// limit_facets.push_back(starting_facet);
// limit_facets.push_back(ending_facet);
// limit_segments.push_back(starting_segment);
// limit_segments.push_back(ending_segment);
// Array<Element> preinserted_facets(2, 1, ElementNull);
// for (UInt i = 0; i < 2; i++) {
// auto it = contour_to_single_facet_map.find(limit_segments(i));
// if (it != contour_to_single_facet_map.end()) {
// preinserted_facets(i) = it->second;
// }
// }
// auto facet_loop = findFacetsLoopByGraphByArea(
// limit_facets, limit_segments, preinserted_facets, cent_node);
// if (not facet_loop.size())
// continue;
// // evaluate average effective stress over facets of the loop
// auto av_eff_stress = averageEffectiveStressInMultipleFacets(facet_loop);
// // if average effective stress exceeds threshold->decompose per mat
// if (av_eff_stress >= av_stress_threshold) {
// decomposeFacetLoopPerMaterial(facet_loop, crack_nb,
// mat_index_facet_nbs_crack_nbs);
// }
// }
// return mat_index_facet_nbs_crack_nbs;
// }
/* --------------------------------------------------------------- */
std::map<UInt, std::map<UInt, UInt>> ASRTools::findStressedFacetsLoops(
const std::map<Element, Element> & contour_subfacets_coh_el,
const std::map<Element, UInt> & /*surface_subfacets_crack_nb*/,
const std::map<UInt, std::set<Element>> & contour_nodes_subfacets,
const std::set<UInt> & /*surface_nodes*/, Real min_dot) {
AKANTU_DEBUG_IN();
const Mesh & mesh = model.getMesh();
const Mesh & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
std::map<UInt, std::map<UInt, UInt>> mat_index_facet_nbs_crack_nbs;
std::map<UInt, std::pair<UInt, Array<Element>>> node_to_crack_nb_facet_loop;
// auto && comm = akantu::Communicator::getWorldCommunicator();
// auto prank = comm.whoAmI();
// clear the nodes_eff_stress array
this->nodes_eff_stress.zero();
// TODO : make iteration on multiple facet types
auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
auto nb_facets = mesh.getNbElement(type_facet);
// skip if no facets of this type are present
if (nb_facets) {
for (auto && pair : contour_nodes_subfacets) {
auto cent_node = pair.first;
auto subfacets = pair.second;
if (subfacets.size() != 2) {
// std::cout << "Number of contour segments connected to the node "
// << cent_node << " is not equal to 2. Skipping" <<
// std::endl;
continue;
}
auto it = subfacets.begin();
auto starting_segment(*it);
std::advance(it, 1);
auto ending_segment(*it);
auto starting_coh_el = contour_subfacets_coh_el.at(starting_segment);
auto ending_coh_el = contour_subfacets_coh_el.at(ending_segment);
auto & crack_numbers = mesh.getData<UInt>(
"crack_numbers", starting_coh_el.type, starting_coh_el.ghost_type);
auto crack_nb = crack_numbers(starting_coh_el.element);
auto starting_facet =
mesh_facets.getSubelementToElement(starting_coh_el)(0);
auto ending_facet = mesh_facets.getSubelementToElement(ending_coh_el)(0);
Array<Element> limit_facets, limit_segments;
limit_facets.push_back(starting_facet);
limit_facets.push_back(ending_facet);
limit_segments.push_back(starting_segment);
limit_segments.push_back(ending_segment);
auto facet_loop = findStressedFacetLoopAroundNode(
limit_facets, limit_segments, cent_node, min_dot);
// store the facet loop in the map
node_to_crack_nb_facet_loop[cent_node] =
std::make_pair(crack_nb, facet_loop);
// evaluate average effective stress over facets of the loop
auto av_eff_stress = averageEffectiveStressInMultipleFacets(facet_loop);
// assign stress value to the node
this->nodes_eff_stress(cent_node) = av_eff_stress;
}
}
// communicate effective stresses by erasing the lowest values
communicateEffStressesOnNodes();
for (auto && pair : node_to_crack_nb_facet_loop) {
auto && cent_node = pair.first;
auto && crack_nb = pair.second.first;
auto && facet_loop = pair.second.second;
if (this->nodes_eff_stress(cent_node) > 0) {
decomposeFacetLoopPerMaterial(facet_loop, crack_nb,
mat_index_facet_nbs_crack_nbs);
}
}
return mat_index_facet_nbs_crack_nbs;
}
/* --------------------------------------------------------------- */
Real ASRTools::averageEffectiveStressInMultipleFacets(
Array<Element> & facet_loop) {
if (not facet_loop.size())
return 0;
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
const FEEngine & fe_engine = model.getFEEngine("FacetsFEEngine");
Array<Real> eff_stress_array;
ElementType type_facet;
GhostType gt;
Array<UInt> facet_nbs;
for (auto & facet : facet_loop) {
type_facet = facet.type;
gt = facet.ghost_type;
facet_nbs.push_back(facet.element);
auto & facet_material_index =
coh_model.getFacetMaterial(type_facet, gt)(facet.element);
auto & mat = model.getMaterial(facet_material_index);
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
if (mat_coh == nullptr)
return 0;
auto && mat_facet_filter = mat_coh->getFacetFilter(type_facet, gt);
UInt facet_local_num = mat_facet_filter.find(facet.element);
AKANTU_DEBUG_ASSERT(facet_local_num != UInt(-1),
"Local facet number was not identified");
auto & eff_stress = mat.getInternal<Real>("effective_stresses")(
type_facet, gt)(facet_local_num);
for (__attribute__((unused)) UInt quad :
arange(fe_engine.getNbIntegrationPoints(type_facet)))
eff_stress_array.push_back(eff_stress);
}
Real int_eff_stress =
fe_engine.integrate(eff_stress_array, type_facet, gt, facet_nbs);
Array<Real> dummy_array(
facet_loop.size() * fe_engine.getNbIntegrationPoints(type_facet), 1, 1.);
Real loop_area = fe_engine.integrate(dummy_array, type_facet, gt, facet_nbs);
return int_eff_stress / loop_area;
}
/* --------------------------------------------------------------- */
void ASRTools::decomposeFacetLoopPerMaterial(
const Array<Element> & facet_loop, UInt crack_nb,
std::map<UInt, std::map<UInt, UInt>> & mat_index_facet_nbs_crack_nbs) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
for (auto & facet : facet_loop) {
ElementType type_facet = facet.type;
GhostType gt = facet.ghost_type;
auto & facet_material_index =
coh_model.getFacetMaterial(type_facet, gt)(facet.element);
mat_index_facet_nbs_crack_nbs[facet_material_index][facet.element] =
crack_nb;
}
}
/* --------------------------------------------------------------- */
void ASRTools::applyEigenOpening(Real eigen_strain) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
if (not coh_model.getIsExtrinsic()) {
AKANTU_EXCEPTION(
"This function can only be used for extrinsic cohesive elements");
}
const Mesh & mesh_facets = coh_model.getMeshFacets();
const UInt dim = model.getSpatialDimension();
for (auto && mat : model.getMaterials()) {
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
if (mat_coh == nullptr)
continue;
for (auto gt : ghost_types) {
for (auto && type_facet : mesh_facets.elementTypes(dim - 1)) {
ElementType type_cohesive =
FEEngine::getCohesiveElementType(type_facet);
UInt nb_quad_cohesive = model.getFEEngine("CohesiveFEEngine")
.getNbIntegrationPoints(type_cohesive);
if (not model.getMesh().getNbElement(type_cohesive, gt))
continue;
const Array<UInt> & elem_filter =
mat_coh->getElementFilter(type_cohesive, gt);
if (not elem_filter.size()) {
continue;
}
// access openings of cohesive elements
auto & eig_opening = mat_coh->getEigenOpening(type_cohesive, gt);
auto & normals = mat_coh->getNormals(type_cohesive, gt);
auto eig_op_it = eig_opening.begin(dim);
auto normals_it = normals.begin(dim);
// apply eigen strain as opening
for (auto el_order : arange(elem_filter.size())) {
Element cohesive{type_cohesive, elem_filter(el_order), gt};
const Vector<Element> & facets_to_cohesive =
mesh_facets.getSubelementToElement(cohesive);
Real facet_indiam = MeshUtils::getInscribedCircleDiameter(
model, facets_to_cohesive(0));
auto eigen_opening = eigen_strain * facet_indiam;
Vector<Real> normal(normals_it[el_order * nb_quad_cohesive]);
for (UInt i : arange(nb_quad_cohesive)) {
auto eig_op = eig_op_it[el_order * nb_quad_cohesive + i];
eig_op = normal * eigen_opening;
}
}
}
}
}
}
// /* --------------------------------------------------------------- */
// void ASRTools::applyEigenOpeningGelVolumeBased(Real gel_volume_ratio) {
// auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
// const Mesh & mesh_facets = coh_model.getMeshFacets();
// const UInt dim = model.getSpatialDimension();
// // compute total asr gel volume
// if (!this->volume)
// computeModelVolume();
// Real gel_volume = this->volume * gel_volume_ratio;
// // compute total area of existing cracks
// auto data_agg = computeCrackData("agg-agg");
// auto data_agg_mor = computeCrackData("agg-mor");
// auto data_mor = computeCrackData("mor-mor");
// auto area_agg = std::get<0>(data_agg);
// auto area_agg_mor = std::get<0>(data_agg_mor);
// auto area_mor = std::get<0>(data_mor);
// Real total_area = area_agg + area_agg_mor + area_mor;
// // compute necessary opening to cover fit gel volume by crack area
// Real average_opening = gel_volume / total_area;
// for (auto && mat : model.getMaterials()) {
// auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
// if (mat_coh == nullptr)
// continue;
// for (auto gt : ghost_types) {
// for (auto && type_facet : mesh_facets.elementTypes(dim - 1)) {
// ElementType type_cohesive =
// FEEngine::getCohesiveElementType(type_facet);
// UInt nb_quad_cohesive = model.getFEEngine("CohesiveFEEngine")
// .getNbIntegrationPoints(type_cohesive);
// if (not model.getMesh().getNbElement(type_cohesive, gt))
// continue;
// const Array<UInt> & elem_filter =
// mat_coh->getElementFilter(type_cohesive, gt);
// if (not elem_filter.size()) {
// continue;
// }
// // access openings of cohesive elements
// auto & eig_opening = mat_coh->getEigenOpening(type_cohesive, gt);
// auto & normals = mat_coh->getNormals(type_cohesive, gt);
// auto eig_op_it = eig_opening.begin(dim);
// auto normals_it = normals.begin(dim);
// // apply average opening directly as eigen
// for (auto el_order : arange(elem_filter.size())) {
// Vector<Real> normal(normals_it[el_order * nb_quad_cohesive]);
// for (UInt i : arange(nb_quad_cohesive)) {
// auto eig_op = eig_op_it[el_order * nb_quad_cohesive + i];
// eig_op = normal * average_opening;
// }
// }
// }
// }
// }
// }
/* --------------------------------------------------------------- */
// void ASRTools::applyEigenOpeningToInitialCrack(
// Real gel_volume_ratio, const Array<Array<Element>> & asr_facets) {
// auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
// const FEEngine & fe_engine = model.getFEEngine("CohesiveFEEngine");
// const UInt dim = model.getSpatialDimension();
// const Mesh & mesh_facets = coh_model.getMeshFacets();
// auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
// ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet);
// UInt nb_quad_cohesive = model.getFEEngine("CohesiveFEEngine")
// .getNbIntegrationPoints(type_cohesive);
// const Array<UInt> & material_index_vec =
// model.getMaterialByElement(type_cohesive);
// const Array<UInt> & material_local_numbering_vec =
// model.getMaterialLocalNumbering(type_cohesive);
// // compute total asr gel volume
// if (!this->volume)
// computeModelVolume();
// Real gel_volume = this->volume * gel_volume_ratio;
// Real gel_volume_per_crack = gel_volume / asr_facets.size();
// // iterate through each crack
// for (auto & single_site_facets : asr_facets) {
// // compute area of current ASR site
// // form cohesive element filter
// std::set<Element> site_cohesives;
// for (auto & asr_facet : single_site_facets) {
// // find connected cohesive
// auto & connected_els = mesh_facets.getElementToSubelement(asr_facet);
// for (auto & connected_el : connected_els) {
// if (connected_el.type == type_cohesive) {
// site_cohesives.emplace(connected_el);
// break;
// }
// }
// }
// // integrate 1 over identified element filter
// Real site_area{0};
// for (auto & coh_el : site_cohesives) {
// Array<UInt> single_el_array;
// single_el_array.push_back(coh_el.element);
// Array<Real> area(fe_engine.getNbIntegrationPoints(type_cohesive),
// 1, 1.); site_area += fe_engine.integrate(area, coh_el.type,
// coh_el.ghost_type,
// single_el_array);
// }
// // compute necessary opening to cover fit gel volume by crack area
// Real average_opening = gel_volume_per_crack / site_area;
// // iterate through each cohesive and apply eigen opening
// for (auto && coh_el : site_cohesives) {
// Material & mat = model.getMaterial(material_index_vec(coh_el.element));
// auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
// if (mat_coh == nullptr)
// continue;
// UInt coh_el_local_num = material_local_numbering_vec(coh_el.element);
// // access openings of cohesive elements
// auto & eig_opening =
// mat_coh->getEigenOpening(coh_el.type, coh_el.ghost_type);
// auto & normals = mat_coh->getNormals(coh_el.type, coh_el.ghost_type);
// auto eig_op_it = eig_opening.begin(dim);
// auto normals_it = normals.begin(dim);
// Vector<Real> normal(normals_it[coh_el_local_num * nb_quad_cohesive]);
// for (UInt i : arange(nb_quad_cohesive)) {
// Vector<Real> eig_op(eig_op_it[coh_el_local_num * nb_quad_cohesive +
// i]); eig_op = normal * average_opening;
// }
// }
// }
// }
/* --------------------------------------------------------------- */
void ASRTools::applyPointForceToAsrCentralNodes(Real force_norm) {
auto && mesh = model.getMesh();
auto dim = mesh.getSpatialDimension();
auto & forces = model.getExternalForce();
auto & pos = mesh.getNodes();
auto it_force = make_view(forces, dim).begin();
auto it_pos = make_view(pos, dim).begin();
for (auto && data : zip(asr_central_node_pairs, asr_normals_pairs)) {
auto && node_pair = std::get<0>(data);
auto && normals_pair = std::get<1>(data);
auto node1 = node_pair.first;
auto node2 = node_pair.second;
auto normal1 = normals_pair.first;
auto normal2 = normals_pair.second;
Vector<Real> force1 = it_force[node1];
Vector<Real> force2 = it_force[node2];
force1 = normal1 * force_norm / 2.;
force2 = normal2 * force_norm / 2.;
}
}
/* --------------------------------------------------------------- */
void ASRTools::applyPointForceDelayed(Real loading_rate,
const Array<Real> loading_times,
Real time, Real multiplier) {
auto && mesh = model.getMesh();
auto dim = mesh.getSpatialDimension();
auto & forces = model.getExternalForce();
auto & pos = mesh.getNodes();
auto it_force = make_view(forces, dim).begin();
auto it_pos = make_view(pos, dim).begin();
AKANTU_DEBUG_ASSERT(loading_times.size() == asr_central_node_pairs.size(),
"Number of starting loading times does not correspond to "
"the number of node pairs");
for (auto && data :
zip(asr_central_node_pairs, asr_normals_pairs, loading_times)) {
auto && node_pair = std::get<0>(data);
auto && normals_pair = std::get<1>(data);
auto && loading_time = std::get<2>(data);
// skip if the crack should not be loaded YET
if (time < loading_time)
continue;
Real force_norm = loading_rate * (time - loading_time) * multiplier;
auto node1 = node_pair.first;
auto node2 = node_pair.second;
auto normal1 = normals_pair.first;
auto normal2 = normals_pair.second;
Vector<Real> force1 = it_force[node1];
Vector<Real> force2 = it_force[node2];
force1 = normal1 * force_norm / 2.;
force2 = normal2 * force_norm / 2.;
}
}
/* --------------------------------------------------------------- */
void ASRTools::applyPointForceDistributed(Real radius, Real F) {
AKANTU_DEBUG_ASSERT(radius != 0, "ASR pocket radius could not be equal to 0");
auto && mesh = model.getMesh();
auto & mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
auto gt = _not_ghost;
auto & forces = model.getExternalForce();
auto & pos = mesh.getNodes();
auto it_force = make_view(forces, dim).begin();
auto it_pos = make_view(pos, dim).begin();
for (auto && data : zip(asr_central_node_pairs, asr_normals_pairs)) {
std::map<std::pair<UInt, UInt>, std::pair<Real, Vector<Real>>>
loaded_nodes_distance_normal;
auto central_node_pair = std::get<0>(data);
auto normals_pair = std::get<1>(data);
if (central_node_pair.first < central_node_pair.second) {
loaded_nodes_distance_normal[central_node_pair] =
std::make_pair(0., normals_pair.first);
} else {
auto copy = central_node_pair;
central_node_pair.first = copy.second;
central_node_pair.second = copy.first;
loaded_nodes_distance_normal[central_node_pair] =
std::make_pair(0., normals_pair.second);
}
auto central_node = central_node_pair.first;
Vector<Real> sphere_center = it_pos[central_node];
// normal opening of central nodes
Vector<Real> central_opening = it_pos[central_node_pair.first];
central_opening -= Vector<Real>(it_pos[central_node_pair.second]);
auto normal_centr_open_norm = central_opening.dot(normals_pair.first);
normal_centr_open_norm = std::abs(normal_centr_open_norm);
// search for cohesives falling into the sphere
for (auto coh_type : mesh.elementTypes(dim, gt, _ek_cohesive)) {
auto && coh_conn = mesh.getConnectivity(coh_type, gt);
auto nb_coh_nodes = coh_conn.getNbComponent();
auto coh_conn_it = coh_conn.begin(coh_conn.getNbComponent());
UInt nb_quad_cohesive = model.getFEEngine("CohesiveFEEngine")
.getNbIntegrationPoints(coh_type);
for (auto && mat : model.getMaterials()) {
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
if (mat_coh == nullptr)
continue;
const auto & filter_map = mat.getElementFilter();
if (!filter_map.exists(coh_type, gt))
continue;
const Array<UInt> & filter = mat.getElementFilter(coh_type, gt);
if (filter.size() == 0)
continue;
auto && damage = mat.getInternal<Real>("damage")(coh_type, gt);
auto && coh_normals = mat_coh->getNormals(coh_type, gt);
auto coh_norm_it = coh_normals.begin(dim);
auto && normal_opening_norm =
mat_coh->getInternal<Real>("normal_opening_norm")(coh_type, gt);
for (auto && data : enumerate(filter)) {
auto local_coh_nb = std::get<0>(data);
auto coh_el_nb = std::get<1>(data);
// consider only fully broken elements
if (damage(local_coh_nb * nb_quad_cohesive) < 1.)
continue;
// consider only elements with big opening
if (normal_opening_norm(local_coh_nb * nb_quad_cohesive) <
0.4 * normal_centr_open_norm)
continue;
Element coh_el{coh_type, coh_el_nb, gt};
auto coh_facet = mesh_facets.getSubelementToElement(coh_el)(0);
Vector<Real> coh_bary(dim);
mesh_facets.getBarycenter(coh_facet, coh_bary);
auto distance = sphere_center.distance(coh_bary);
// quickly discard if cohesive is further from the center
if (distance >= radius)
continue;
// otherwise check nodes
auto coh_nodes = coh_conn_it[coh_el_nb];
std::map<UInt, UInt> counts;
for (auto i : coh_nodes)
++counts[i];
auto nb_duplicated_nodes =
std::count_if(counts.begin(), counts.end(),
[](auto const & p) { return p.second == 1; });
// discard cohesives with not all nodes opened
if (nb_duplicated_nodes != nb_coh_nodes)
continue;
// otherwise add all node pairs into the set
for (UInt i : arange(nb_coh_nodes / 2)) {
Vector<Real> node_coord = it_pos[coh_nodes(i)];
auto distance = sphere_center.distance(node_coord);
// exclude nodes falling outside the sphere
if (distance <= radius) {
Vector<Real> coh_normal =
coh_norm_it[local_coh_nb * nb_quad_cohesive];
std::pair<UInt, UInt> nodes_pair;
Vector<Real> corr_normal(dim);
if (coh_nodes(i) < coh_nodes(i + nb_coh_nodes / 2)) {
nodes_pair = std::make_pair(coh_nodes(i),
coh_nodes(i + nb_coh_nodes / 2));
corr_normal = coh_normal;
} else {
nodes_pair = std::make_pair(coh_nodes(i + nb_coh_nodes / 2),
coh_nodes(i));
corr_normal = -1. * coh_normal;
}
if (loaded_nodes_distance_normal.find(nodes_pair) ==
loaded_nodes_distance_normal.end()) {
loaded_nodes_distance_normal[nodes_pair] =
std::make_pair(distance, corr_normal);
}
}
}
}
}
}
// compute central loading
Real denominator{0};
for (auto && pair : loaded_nodes_distance_normal) {
denominator += 1 - pair.second.first / radius;
}
auto central_load = F / 2 / denominator;
// distribute loading between all the node pairs
for (auto && pair : loaded_nodes_distance_normal) {
auto node_pair = pair.first;
auto distance = pair.second.first;
auto normal = pair.second.second;
auto node1 = node_pair.first;
auto node2 = node_pair.second;
Vector<Real> force1 = it_force[node1];
Vector<Real> force2 = it_force[node2];
force1 = normal * central_load * (1 - distance / radius);
force2 = -1. * normal * central_load * (1 - distance / radius);
}
}
}
/* --------------------------------------------------------------- */
void ASRTools::applyPointForcesFacetLoop(Real load) {
auto && mesh = model.getMesh();
auto dim = mesh.getSpatialDimension();
auto & forces = model.getExternalForce();
auto it_force = make_view(forces, dim).begin();
CSR<Element> nodes_to_cohesives;
MeshUtils::buildNode2Elements(mesh, nodes_to_cohesives, dim, _ek_cohesive);
for (auto && data : zip(asr_central_node_pairs)) {
std::map<std::pair<UInt, UInt>, Vector<Real>> loaded_nodes_normals;
std::set<std::pair<UInt, UInt>> loaded_nodes;
auto central_node_pair = std::get<0>(data);
auto central_node = central_node_pair.first;
for (auto & coh : nodes_to_cohesives.getRow(central_node)) {
// check duplicated nodes
auto coh_nodes = mesh.getConnectivity(coh);
auto nb_coh_nodes = coh_nodes.size();
auto nb_quad_cohesive = model.getFEEngine("CohesiveFEEngine")
.getNbIntegrationPoints(coh.type);
auto mat_id =
model.getMaterialByElement(coh.type, coh.ghost_type)(coh.element);
auto coh_loc_num = model.getMaterialLocalNumbering(
coh.type, coh.ghost_type)(coh.element);
auto && mat = model.getMaterial(mat_id);
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
auto && coh_normals = mat_coh->getNormals(coh.type, coh.ghost_type);
auto coh_norm_it = coh_normals.begin(dim);
Vector<Real> coh_normal = coh_norm_it[coh_loc_num * nb_quad_cohesive];
std::pair<UInt, UInt> nodes_pair;
for (UInt i : arange(nb_coh_nodes / 2)) {
if (coh_nodes(i) != coh_nodes(i + nb_coh_nodes / 2)) {
nodes_pair.first =
std::min(coh_nodes(i), coh_nodes(i + nb_coh_nodes / 2));
nodes_pair.second =
std::max(coh_nodes(i), coh_nodes(i + nb_coh_nodes / 2));
Vector<Real> corr_normal = coh_normal;
if (nodes_pair.first != coh_nodes(i))
corr_normal *= -1.;
auto res = loaded_nodes.insert(nodes_pair);
if (res.second == true) {
loaded_nodes_normals[nodes_pair] = corr_normal;
} else {
loaded_nodes_normals[nodes_pair] += corr_normal;
}
}
}
}
// sum up all previously applied forces
Real current_load{0};
for (auto && pair : loaded_nodes_normals) {
auto node_pair = pair.first;
auto node1 = node_pair.first;
auto node2 = node_pair.second;
Vector<Real> force1 = it_force[node1];
Vector<Real> force2 = it_force[node2];
current_load += std::abs(force1.norm()) + std::abs(force2.norm());
}
Real load_incr = load - current_load;
// split load increase between all the node pairs
for (auto && pair : loaded_nodes_normals) {
auto node_pair = pair.first;
auto normal = pair.second;
if (not Math::are_float_equal(normal.norm(), 0))
normal /= normal.norm();
auto node1 = node_pair.first;
auto node2 = node_pair.second;
Vector<Real> force1 = it_force[node1];
Vector<Real> force2 = it_force[node2];
force1 += normal * load_incr / 2. / Real(loaded_nodes_normals.size());
force2 +=
-1. * normal * load_incr / 2. / Real(loaded_nodes_normals.size());
}
}
}
/* --------------------------------------------------------------- */
void ASRTools::outputCrackData(std::ofstream & file_output, Real time) {
auto data_agg = computeCrackData("agg-agg");
auto data_agg_mor = computeCrackData("agg-mor");
auto data_mor = computeCrackData("mor-mor");
auto area_agg = std::get<0>(data_agg);
auto vol_agg = std::get<1>(data_agg);
// auto asr_vol_agg = std::get<2>(data_agg);
auto area_agg_mor = std::get<0>(data_agg_mor);
auto vol_agg_mor = std::get<1>(data_agg_mor);
// auto asr_vol_agg_mor = std::get<2>(data_agg_mor);
auto area_mor = std::get<0>(data_mor);
auto vol_mor = std::get<1>(data_mor);
// auto asr_vol_mor = std::get<2>(data_mor);
Real total_area = area_agg + area_agg_mor + area_mor;
Real total_volume = vol_agg + vol_agg_mor + vol_mor;
// Real asr_volume = asr_vol_agg + asr_vol_agg_mor + asr_vol_mor;
auto && comm = akantu::Communicator::getWorldCommunicator();
auto prank = comm.whoAmI();
if (prank == 0) {
file_output << time << "," << area_agg << "," << area_agg_mor << ","
<< area_mor << "," << vol_agg << "," << vol_agg_mor << ","
<< vol_mor << "," << total_area << "," << total_volume
<< std::endl;
}
}
/* --------------------------------------------------------------- */
std::tuple<Real, Real> ASRTools::computeCrackData(const ID & material_name) {
const auto & mesh = model.getMesh();
const auto & mesh_facets = mesh.getMeshFacets();
const auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
Material & mat = model.getMaterial(material_name);
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
AKANTU_DEBUG_ASSERT(mat_coh != nullptr,
"Crack data can not be computed on material with id" +
material_name);
const ElementTypeMapArray<UInt> & filter_map = mat_coh->getElementFilter();
const FEEngine & fe_engine = model.getFEEngine("CohesiveFEEngine");
Real crack_volume{0};
Real crack_area{0};
// Real ASR_volume{0};
// Loop over the cohesive element types
for (auto & element_type : filter_map.elementTypes(dim, gt, _ek_cohesive)) {
const Array<UInt> & filter = filter_map(element_type);
if (!filter_map.exists(element_type, gt))
continue;
if (filter.size() == 0)
continue;
UInt nb_quad_cohesive = model.getFEEngine("CohesiveFEEngine")
.getNbIntegrationPoints(element_type);
/// compute normal norm of real opening = opening + eigen opening
auto opening_it = mat_coh->getOpening(element_type, gt).begin(dim);
auto eigen_opening = mat_coh->getEigenOpening(element_type, gt);
auto eigen_opening_it = eigen_opening.begin(dim);
Array<Real> normal_eigen_opening_norm(
filter.size() * fe_engine.getNbIntegrationPoints(element_type), 1, 0);
auto normal_eigen_opening_norm_it = normal_eigen_opening_norm.begin();
Array<Real> real_normal_opening_norm(
filter.size() * fe_engine.getNbIntegrationPoints(element_type), 1, 0);
auto real_normal_opening_norm_it = real_normal_opening_norm.begin();
auto normal_it = mat_coh->getNormals(element_type, gt).begin(dim);
auto normal_end = mat_coh->getNormals(element_type, gt).end(dim);
/// loop on each quadrature point
for (UInt i = 0; normal_it != normal_end; ++i, ++opening_it,
++eigen_opening_it, ++normal_it, ++real_normal_opening_norm_it,
++normal_eigen_opening_norm_it) {
UInt coh_nb = filter(floor(i / nb_quad_cohesive));
Element coh{element_type, coh_nb, gt};
auto && coh_facets = mesh_facets.getSubelementToElement(coh);
bool blowed_up{false};
for (auto & coh_facet : coh_facets) {
// auto inscr_diam_init =
// MeshUtils::getInscribedCircleDiameter(model, coh_facet, true);
// auto inscr_diam_curr =
// MeshUtils::getInscribedCircleDiameter(model, coh_facet, false);
// if (inscr_diam_curr >= 2 * inscr_diam_init) {
auto initial_area = MeshUtils::getFacetArea(model, coh_facet);
auto current_area = MeshUtils::getCurrentFacetArea(model, coh_facet);
if (current_area >= 2 * initial_area) {
blowed_up = true;
break;
}
}
if (blowed_up)
continue;
auto real_opening = *opening_it + *eigen_opening_it;
*real_normal_opening_norm_it = real_opening.dot(*normal_it);
Vector<Real> eig_opening(*eigen_opening_it);
*normal_eigen_opening_norm_it = eig_opening.dot(*normal_it);
}
crack_volume =
fe_engine.integrate(real_normal_opening_norm, element_type, gt, filter);
Array<Real> area(
filter.size() * fe_engine.getNbIntegrationPoints(element_type), 1, 1.);
crack_area = fe_engine.integrate(area, element_type, gt, filter);
}
auto && comm = akantu::Communicator::getWorldCommunicator();
// comm.allReduce(ASR_volume, SynchronizerOperation::_sum);
comm.allReduce(crack_volume, SynchronizerOperation::_sum);
comm.allReduce(crack_area, SynchronizerOperation::_sum);
return std::make_tuple(crack_area, crack_volume);
}
/* --------------------------------------------------------------- */
void ASRTools::outputCrackVolumes(std::ofstream & file_output, Real time) {
const Communicator & comm = Communicator::getWorldCommunicator();
UInt prank = comm.whoAmI();
// shift crack numbers by the number of cracks on lower processors
UInt tot_nb_cracks{asr_central_node_pairs.size()};
comm.allReduce(tot_nb_cracks, SynchronizerOperation::_sum);
Array<Real> crack_volumes(tot_nb_cracks, 1, 0.);
const FEEngine & fe_engine = model.getFEEngine("CohesiveFEEngine");
auto && mesh = model.getMesh();
auto && mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
GhostType gt = _not_ghost;
for (auto coh_type : mesh.elementTypes(dim, gt, _ek_cohesive)) {
auto & crack_numbers = mesh.getData<UInt>("crack_numbers", coh_type, gt);
for (auto && mat : model.getMaterials()) {
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
if (mat_coh == nullptr)
continue;
const auto & filter_map = mat_coh->getElementFilter();
if (!filter_map.exists(coh_type, gt))
continue;
const Array<UInt> & filter = mat_coh->getElementFilter(coh_type, gt);
if (filter.size() == 0)
continue;
UInt nb_quad_cohesive = model.getFEEngine("CohesiveFEEngine")
.getNbIntegrationPoints(coh_type);
/// compute normal norm of real opening = opening + eigen opening
auto opening_it = mat_coh->getOpening(coh_type, gt).begin(dim);
auto eigen_opening = mat_coh->getEigenOpening(coh_type, gt);
auto eigen_opening_it = eigen_opening.begin(dim);
Array<Real> normal_eigen_opening_norm(
filter.size() * fe_engine.getNbIntegrationPoints(coh_type), 1, 0);
auto normal_eigen_opening_norm_it = normal_eigen_opening_norm.begin();
Array<Real> real_normal_opening_norm(
filter.size() * fe_engine.getNbIntegrationPoints(coh_type), 1, 0);
Array<Real> open_volume(filter.size());
auto real_normal_opening_norm_it = real_normal_opening_norm.begin();
auto normal_it = mat_coh->getNormals(coh_type, gt).begin(dim);
auto normal_end = mat_coh->getNormals(coh_type, gt).end(dim);
/// loop on each quadrature point
for (UInt i = 0; normal_it != normal_end; ++i, ++opening_it,
++eigen_opening_it, ++normal_it, ++real_normal_opening_norm_it,
++normal_eigen_opening_norm_it) {
UInt coh_nb = filter(floor(i / nb_quad_cohesive));
Element coh{coh_type, coh_nb, gt};
auto && coh_facets = mesh_facets.getSubelementToElement(coh);
bool blowed_up{false};
for (auto & coh_facet : coh_facets) {
auto inscr_diam_init =
MeshUtils::getInscribedCircleDiameter(model, coh_facet, true);
auto inscr_diam_curr =
MeshUtils::getInscribedCircleDiameter(model, coh_facet, false);
if (inscr_diam_curr >= 2 * inscr_diam_init) {
blowed_up = true;
break;
}
}
if (blowed_up)
continue;
auto real_opening = *opening_it + *eigen_opening_it;
*real_normal_opening_norm_it = real_opening.dot(*normal_it);
Vector<Real> eig_opening(*eigen_opening_it);
*normal_eigen_opening_norm_it = eig_opening.dot(*normal_it);
}
fe_engine.integrate(real_normal_opening_norm, open_volume, 1, coh_type,
gt, filter);
// distribute individual crack volumes per crack number
for (UInt i : arange(filter.size())) {
auto coh_el = filter(i);
auto crack_nb = crack_numbers(coh_el);
crack_volumes(crack_nb) += open_volume(i);
}
}
}
comm.allReduce(crack_volumes, SynchronizerOperation::_sum);
// output into a file
if (prank == 0) {
file_output << time;
for (auto && single_vol : crack_volumes) {
file_output << "," << single_vol;
}
file_output << std::endl;
}
}
/* --------------------------------------------------------------- */
void ASRTools::outputCrackOpenings(std::ofstream & file_output, Real time) {
const Communicator & comm = Communicator::getWorldCommunicator();
UInt prank = comm.whoAmI();
UInt nb_proc = comm.getNbProc();
Real global_nb_openings(asr_central_node_pairs.size());
comm.allReduce(global_nb_openings, SynchronizerOperation::_sum);
/// shift crack numbers by the number of cracks on lower processors
UInt nb_cracks{asr_central_node_pairs.size()};
comm.exclusiveScan(nb_cracks);
UInt max_nb_cracks{asr_central_node_pairs.size()};
comm.allReduce(max_nb_cracks, SynchronizerOperation::_max);
Array<Real> openings(nb_proc, max_nb_cracks, -1.);
auto && mesh = model.getMesh();
auto dim = mesh.getSpatialDimension();
auto & disp = model.getDisplacement();
auto & pos = mesh.getNodes();
auto it_disp = make_view(disp, dim).begin();
auto it_pos = make_view(pos, dim).begin();
auto it_open = make_view(openings, max_nb_cracks).begin();
auto open_end = make_view(openings, max_nb_cracks).end();
for (UInt i = 0; i < asr_central_node_pairs.size(); i++) {
auto && node_pair = asr_central_node_pairs(i);
auto && normals_pair = asr_normals_pairs(i);
auto node1 = node_pair.first;
auto node2 = node_pair.second;
auto normal1 = normals_pair.first;
Vector<Real> disp1 = it_disp[node1];
Vector<Real> disp2 = it_disp[node2];
Vector<Real> rel_disp = disp1 - disp2;
Real norm_opening = rel_disp.dot(normal1);
openings(prank, i) = norm_opening;
}
comm.allGather(openings);
if (prank == 0) {
file_output << time;
for (; it_open != open_end; ++it_open) {
Vector<Real> openings_per_proc = *it_open;
for (auto && opening : openings_per_proc) {
if (opening != -1.) {
file_output << "," << opening;
}
}
}
file_output << std::endl;
}
}
/* --------------------------------------------------------------- */
void ASRTools::outputCrackOpeningsPerProc(std::ofstream & file_output,
Real time) {
Array<Real> openings(asr_central_node_pairs.size());
auto && mesh = model.getMesh();
auto dim = mesh.getSpatialDimension();
auto & disp = model.getDisplacement();
auto & pos = mesh.getNodes();
auto it_disp = make_view(disp, dim).begin();
auto it_pos = make_view(pos, dim).begin();
for (UInt i = 0; i < asr_central_node_pairs.size(); i++) {
auto && node_pair = asr_central_node_pairs(i);
auto && normals_pair = asr_normals_pairs(i);
auto node1 = node_pair.first;
auto node2 = node_pair.second;
auto normal1 = normals_pair.first;
Vector<Real> disp1 = it_disp[node1];
Vector<Real> disp2 = it_disp[node2];
Vector<Real> rel_disp = disp1 - disp2;
Real norm_opening = rel_disp.dot(normal1);
openings(i) = norm_opening;
}
file_output << time;
for (auto && opening : openings) {
file_output << "," << opening;
}
file_output << std::endl;
}
/* --------------------------------------------------------------- */
void ASRTools::identifyASRCentralNodePairsAndNormals() {
auto && mesh = model.getMesh();
auto && mesh_facets = mesh.getMeshFacets();
auto dim = mesh.getSpatialDimension();
auto & forces = model.getExternalForce();
auto & pos = mesh.getNodes();
auto type_facet = *mesh_facets.elementTypes(dim - 1).begin();
auto && fe_engine = model.getFEEngine("FacetsFEEngine");
UInt nb_quad_points = fe_engine.getNbIntegrationPoints(type_facet);
// get normal to the initial positions
const auto & init_pos = mesh.getNodes();
Array<Real> quad_normals(0, dim);
fe_engine.computeNormalsOnIntegrationPoints(init_pos, quad_normals,
type_facet);
auto normals_it = quad_normals.begin(dim);
auto it_force = make_view(forces, dim).begin();
auto it_pos = make_view(pos, dim).begin();
this->asr_central_node_pairs.resize(asr_facets.size());
this->asr_normals_pairs.resize(asr_facets.size());
for (auto && data :
zip(asr_facets, asr_central_node_pairs, asr_normals_pairs)) {
auto && facets_per_site = std::get<0>(data);
auto & node_pair = std::get<1>(data);
node_pair = std::make_pair(UInt(-1), UInt(-1));
auto & asr_normals_pair = std::get<2>(data);
// find first node
auto && facet_conn = mesh_facets.getConnectivity(facets_per_site(0));
for (auto && node : facet_conn) {
auto ret = asr_central_nodes.find(node);
if (ret != UInt(-1)) {
node_pair.first = node;
break;
}
}
AKANTU_DEBUG_ASSERT(node_pair.first != UInt(-1),
"First node was not identified");
// compute first normal
Vector<Real> normal(dim, 0);
for (auto && facet : facets_per_site) {
// skip out opposite side facets
auto && facet_nodes = mesh_facets.getConnectivity(facet);
auto ret =
std::find(facet_nodes.begin(), facet_nodes.end(), node_pair.first);
if (ret == facet_nodes.end()) {
continue;
}
// find connected solid element
auto && facet_neighbors = mesh_facets.getElementToSubelement(facet);
Element solid_el{ElementNull};
for (auto && neighbor : facet_neighbors) {
if (mesh.getKind(neighbor.type) == _ek_regular) {
solid_el = neighbor;
break;
}
}
AKANTU_DEBUG_ASSERT(solid_el != ElementNull,
"Couldn't identify neighboring solid el");
// find the out-of-plane solid node
auto && solid_nodes = mesh.getConnectivity(solid_el);
auto it =
std::find(solid_nodes.begin(), solid_nodes.end(), node_pair.first);
AKANTU_DEBUG_ASSERT(it != solid_nodes.end(),
"Solid el does not contain central node");
UInt out_node(-1);
for (auto && solid_node : solid_nodes) {
auto ret =
std::find(facet_nodes.begin(), facet_nodes.end(), solid_node);
if (ret == facet_nodes.end()) {
out_node = solid_node;
break;
}
}
AKANTU_DEBUG_ASSERT(out_node != UInt(-1),
"Couldn't identify out-of-plane node");
// build the reference vector
Vector<Real> ref_vector(dim);
mesh_facets.getBarycenter(facet, ref_vector);
Vector<Real> pos(mesh.getNodes().begin(dim)[out_node]);
ref_vector = pos - ref_vector;
// check if ref vector and the normal are in the same half space
Vector<Real> facet_normal = normals_it[facet.element * nb_quad_points];
if (ref_vector.dot(facet_normal) < 0) {
facet_normal *= -1;
}
normal += facet_normal;
}
asr_normals_pair.first = normal / normal.norm();
asr_normals_pair.second = normal / normal.norm() * (-1.);
// find the second one
Vector<Real> first_node_pos = it_pos[node_pair.first];
for (auto && asr_central_node : asr_central_nodes) {
Vector<Real> node_pos = it_pos[asr_central_node];
if ((first_node_pos == node_pos) &&
(asr_central_node != node_pair.first)) {
node_pair.second = asr_central_node;
break;
}
}
AKANTU_DEBUG_ASSERT(node_pair.second != UInt(-1),
"Second node was not identified");
}
}
/* ----------------------------------------------------------------- */
std::tuple<std::map<Element, Element>, std::map<Element, UInt>, std::set<UInt>,
std::map<UInt, std::set<Element>>>
ASRTools::determineCrackSurface() {
AKANTU_DEBUG_IN();
Mesh & mesh = model.getMesh();
const Mesh & mesh_facets = mesh.getMeshFacets();
const UInt dim = mesh.getSpatialDimension();
std::map<Element, Element> contour_subfacets_coh_el;
std::map<Element, UInt> surface_subfacets_crack_nb;
std::set<UInt> surface_nodes;
std::map<UInt, std::set<Element>> contour_nodes_subfacets;
std::set<Element> visited_subfacets;
// // first loop on facets (doesn't include duplicated ones)
// for (auto & type_facet :
// mesh.elementTypes(dim - 1, _not_ghost, _ek_regular)) {
// auto nb_facets = mesh.getNbElement(type_facet);
// std::cout << "Nb facets = " << nb_facets << std::endl;
// if (not nb_facets) {
// continue;
// }
// for (auto facet_nb : arange(nb_facets)) {
// Element facet{type_facet, facet_nb, _not_ghost};
// searchCrackSurfaceInSingleFacet(
// facet, contour_subfacets_coh_el, surface_subfacets_crack_nb,
// surface_nodes, contour_nodes_subfacets, visited_subfacets);
// }
// }
// second loop on cohesives (includes duplicated facets)
for (auto gt : ghost_types) {
for (auto & type_cohesive : mesh.elementTypes(dim, gt, _ek_cohesive)) {
auto nb_cohesives = mesh.getNbElement(type_cohesive, gt);
if (not nb_cohesives) {
continue;
}
for (auto cohesive_nb : arange(nb_cohesives)) {
Element cohesive{type_cohesive, cohesive_nb, gt};
auto && facets_to_cohesive =
mesh_facets.getSubelementToElement(cohesive);
for (auto coh_facet : facets_to_cohesive) {
searchCrackSurfaceInSingleFacet(
coh_facet, contour_subfacets_coh_el, surface_subfacets_crack_nb,
surface_nodes, contour_nodes_subfacets, visited_subfacets);
}
}
}
}
// remove external nodes from the surface nodes list
// for (auto & pair : contour_nodes_subfacets) {
// surface_nodes.erase(pair.first);
// }
return std::make_tuple(contour_subfacets_coh_el, surface_subfacets_crack_nb,
surface_nodes, contour_nodes_subfacets);
}
/* ----------------------------------------------------------------- */
void ASRTools::searchCrackSurfaceInSingleFacet(
Element & facet, std::map<Element, Element> & contour_subfacets_coh_el,
std::map<Element, UInt> & /*surface_subfacets_crack_nb*/,
std::set<UInt> & /*surface_nodes*/,
std::map<UInt, std::set<Element>> & contour_nodes_subfacets,
std::set<Element> & visited_subfacets) {
Mesh & mesh = model.getMesh();
const Mesh & mesh_facets = mesh.getMeshFacets();
// iterate through subfacets of a facet searching for cohesives
auto && subfacets_to_facet = mesh_facets.getSubelementToElement(facet);
for (auto & subfacet : subfacets_to_facet) {
// discard subfacets on the border of ghost area
if (subfacet == ElementNull)
continue;
// discard pure ghost subfacets
bool pure_ghost_subf{false};
auto && subfacet_conn = mesh_facets.getConnectivity(subfacet);
for (auto & subfacet_node : subfacet_conn) {
if (mesh.isPureGhostNode(subfacet_node))
pure_ghost_subf = true;
}
if (pure_ghost_subf)
continue;
auto ret = visited_subfacets.emplace(subfacet);
if (not ret.second)
continue;
std::map<Element, UInt> connected_cohesives;
auto && facets_to_subfacet = mesh_facets.getElementToSubelement(subfacet);
for (auto & neighbor_facet : facets_to_subfacet) {
auto & connected_to_facet =
mesh_facets.getElementToSubelement(neighbor_facet);
for (auto & connected_el : connected_to_facet) {
if (connected_el.type == _not_defined)
goto nextfacet;
if (mesh.getKind(connected_el.type) == _ek_cohesive) {
connected_cohesives[connected_el]++;
}
}
nextfacet:;
}
if (connected_cohesives.size() == 1 and
connected_cohesives.begin()->second == 2) {
contour_subfacets_coh_el[subfacet] = connected_cohesives.begin()->first;
Vector<UInt> contour_subfacet_nodes =
mesh_facets.getConnectivity(subfacet);
for (auto & contour_subfacet_node : contour_subfacet_nodes) {
contour_nodes_subfacets[contour_subfacet_node].emplace(subfacet);
}
}
// else if (connected_cohesives.size() > 1) {
// auto coh_element = connected_cohesives.begin()->first;
// UInt crack_nb =
// mesh.getData<UInt>("crack_numbers", coh_element.type,
// coh_element.ghost_type)(coh_element.element);
// surface_subfacets_crack_nb[subfacet] = crack_nb;
// // add subfacet nodes to the set
// for (auto & subfacet_node : mesh_facets.getConnectivity(subfacet))
// surface_nodes.emplace(subfacet_node);
// }
}
}
/* ------------------------------------------------------------------- */
template <UInt dim> UInt ASRTools::updateDeltaMax() {
AKANTU_DEBUG_IN();
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
if (not coh_model.getIsExtrinsic()) {
AKANTU_EXCEPTION(
"This function can only be used for extrinsic cohesive elements");
}
UInt nb_updated_quads(0);
for (auto && mat : model.getMaterials()) {
auto * mat_coh =
dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
if (mat_coh == nullptr)
continue;
for (auto type : mat_coh->getElementFilter().elementTypes(dim, _not_ghost,
_ek_cohesive)) {
nb_updated_quads += mat_coh->updateDeltaMax(type, _not_ghost);
}
}
// summ all updated quads
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(nb_updated_quads, SynchronizerOperation::_sum);
AKANTU_DEBUG_OUT();
return nb_updated_quads;
}
template UInt ASRTools::updateDeltaMax<2>();
template UInt ASRTools::updateDeltaMax<3>();
/* ------------------------------------------------------------------- */
template <UInt dim>
std::tuple<Real, Element, UInt> ASRTools::getMaxDeltaMaxExcess() {
AKANTU_DEBUG_IN();
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
coh_model.interpolateStress();
coh_model.assembleInternalForces();
Real proc_max_delta_max_excess{0};
Element critical_coh_el{ElementNull};
UInt global_nb_penetr_quads{0};
for (auto && mat : model.getMaterials()) {
auto * mat_coh =
dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
if (mat_coh == nullptr)
continue;
for (auto type : mat_coh->getElementFilter().elementTypes(dim, _not_ghost,
_ek_cohesive)) {
auto data = mat_coh->computeMaxDeltaMaxExcess(type, _not_ghost);
auto mat_max_delta_max_excess = std::get<0>(data);
global_nb_penetr_quads += std::get<2>(data);
if (mat_max_delta_max_excess > proc_max_delta_max_excess) {
proc_max_delta_max_excess = mat_max_delta_max_excess;
critical_coh_el = std::get<1>(data);
}
}
}
// communicate the highest excess over different processors
auto global_max_delta_max = proc_max_delta_max_excess;
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(global_max_delta_max, SynchronizerOperation::_max);
comm.allReduce(global_nb_penetr_quads, SynchronizerOperation::_sum);
// find the critical coh between processors
if (global_max_delta_max) {
UInt coh_nb = critical_coh_el.element;
if (proc_max_delta_max_excess != global_max_delta_max) {
coh_nb = 0;
}
comm.allReduce(coh_nb, SynchronizerOperation::_max);
critical_coh_el.element = coh_nb;
}
AKANTU_DEBUG_OUT();
return std::make_tuple(global_max_delta_max, critical_coh_el,
global_nb_penetr_quads);
}
template std::tuple<Real, Element, UInt> ASRTools::getMaxDeltaMaxExcess<2>();
template std::tuple<Real, Element, UInt> ASRTools::getMaxDeltaMaxExcess<3>();
/* ------------------------------------------------------------------ */
Real ASRTools::preventCohesiveInsertionInMaterial(std::string facet_mat_name) {
auto & coh_model = dynamic_cast<SolidMechanicsModelCohesive &>(model);
auto & inserter = coh_model.getElementInserter();
auto & mesh = model.getMesh();
auto dim = mesh.getSpatialDimension();
const GhostType gt = _not_ghost;
auto facet_material_id = model.getMaterialIndex(facet_mat_name);
auto & mat = model.getMaterial(facet_material_id);
auto * mat_coh = dynamic_cast<MaterialCohesive *>(&mat);
AKANTU_DEBUG_ASSERT(mat_coh != nullptr, "Chosen material is not cohesive");
auto && facets = mat_coh->getFacetFilter();
UInt facets_excluded{0};
for (const auto & el_type : facets.elementTypes(dim - 1, gt, _ek_regular)) {
auto && element_ids = facets(el_type, gt);
for (auto && el_id : element_ids) {
inserter.getCheckFacets(el_type, gt)(el_id) = false;
facets_excluded++;
}
}
auto && comm = akantu::Communicator::getWorldCommunicator();
comm.allReduce(facets_excluded, SynchronizerOperation::_sum);
return facets_excluded;
}
/* ------------------------------------------------------------------- */
template <UInt dim> void ASRTools::setUpdateStiffness(bool update_stiffness) {
AKANTU_DEBUG_IN();
for (auto && mat : model.getMaterials()) {
auto * mat_coh =
dynamic_cast<MaterialCohesiveLinearSequential<dim> *>(&mat);
if (mat_coh == nullptr)
continue;
mat_coh->setUpdateStiffness(update_stiffness);
}
AKANTU_DEBUG_OUT();
}
template void ASRTools::setUpdateStiffness<2>(bool update_stiffness);
template void ASRTools::setUpdateStiffness<3>(bool update_stiffness);
} // namespace akantu

Event Timeline